Coding Mini Project
Material Developed by: Sanchit Batra, Elijah Einstein, Sean Mackay, Supratik Neupane, Tom Sherwood, Veronica Vitale and Atri Rudra.
Acknowledgment
The development of the coding component of the mini-project was supported by a Mozilla Responsible Computer Science award . The support is gratefully acknowledged.
Some Suggestions and Warnings
While this coding mini-project is somewhat similar to Question 3s on the homework, there are some crucial differences and we wanted to highlight few things for y'all upfront:
Form groups of size $\le 3$
This is a group project (unlike Q3s on the HWs that had to be done individually) and you can work in groups of size at most 3. The submissions will be on Autolab and everyone in the group will get the same grade. The project will be challenging so we highly recommend that you form a group of size at least 2 to make the workload reasonable.
Groups should agree on one programming language
While the submission in this project can be done in any of C++,Java
and Python
like in Question 3s on the homework, we highly recommend that the group agrees on one programming language for the group. This will make it much easier for your group to make progress and collaborate.
The same group for ALL problems
You are expected to work in the same group for ALL problems in the coding project. Not doing so will be considered to be an academic integrity violation. Please note that you will have to sign up your group separately for each problem on Autolab and we will check for group consistency at the end of the semester. So please make sure you follow this rule.
There is ONE exception to the above rule: It is OK if the group becomes smaller (e.g. if a group member resigns) but in that case another student cannot be added to group. If you need clarification on this, please get in touch with Atri.
There are no optimal algorithms known!
Other than the first problem, we do not know of optimal algorithms to solve the rest of the problems and we suspect that doing so is not possible (definitely not within a semester). Note that this is unlike the HW Q3s where your code is supposed to always output the optimal/correct solution: i.e. you will have to think of algorithms where you might not be able to prove any guarantee on how good your output is.
Start early!
There is a reason we are giving y'all about two months to do this project. If your group starts even the week before the project is due, your group will be in trouble especially beyond the first problem. Also for most problems you will have to think of algorithms beyond what we cover in class, so the more time your spend on this, the better.
Optimizing the runtime of your code is NOT the main objective
Unlike the HW Q3s, there will be no timeouts for individual inputs (though there will be one overall per submission). This is because unlike the HW Q3s, the main goal in this coding project submissions will be to generate as much "revenue" as possible (read on for more details on this)-- optimizing the runtime would/should be a secondary object but again there is an overall timeout so really inefficient implementations (and definitely not polynomial runtime algorithms) will not make the cut.
Background
Today reliable internet service is not a luxury, it is a necessity . In February 2017, a lawsuit was filed by New York states Attorney General Eric Schneiderman against Spectrum
, which is a telecommunications company and also the largest provider of residential internet services in New York state. See e.g. the following from the AG's summons and complaint page 6 and point 2:
....Spectrum-TWC is the largest provider of residential Internet services in New York State. It provides Internet service to approximately 2.5 million New York households and earns well over a billion dollars in revenue annually from selling Internet services in New York.
Spectrum
was accused of fraudulently misleading its Internet services customers by promising internet speeds that it knew it could not provide. Spectrum
provided its customers with old generation modems and routers that it knew were incapable of achieving the promised internet speeds. Moreover, they are also accused of capping the bandwidth of routers in order to cut down on expenses and maximize their profit. There were more allegations against Spectrum
. Here is the official lawsuit complaint against Spectrum with all the allegations.
Click here to see a summary of the allegations
- Promised internet speeds differed from actual internet speeds,
Spectrum
made false advertisements and repeatedly assured its customers that they could achieve the same results with wireless as with a wired connection (even though wireless connection has other real world limitations). - Leased out older models of routers that were incapable of achieving the promised speeds (D1 and D2 as opposed to D3) due to “budget constraints” (maximizing profit).
- Charged customers based on the prices advertised for the higher speed plans (the motive for said advertisement was to prevent subscribers from switching ISPs).
- Promised to upgrade the routers without additional charges when tech improved but didn’t despite complaints from customers about the slow internet speed.
- Even the current generation routers did not deliver the speed they had promised, since too many subscribers were grouped into the same service group (less bandwidth available per subscriber) and the number of channels did not increase (which could have increased the bandwidth). Only made modifications when the situation was dire. This led to an abysmal performance during peak hours.
- Deceived the FCC by benchmarking speed during non-peak hours (and hence overestimating performance).
- Changed modems for the FCC panelists doing the benchmarking but not for customers. The FCC results, as a result, painted them in a better light.
- Did not invest in additional ports (cost per Gbps) to content providers which could have decreased latency/buffering/downtimes despite promising the opposite to consumers. In fact, leveraged their access to subscribers by extracting fees from content providers and delivering nothing in return, throttled the rate of content delivery in the absence of payments.
- Started charging a monthly leasing fee for the same modems for which there had previously been no charge.
- Customers were allowed to upgrade their modems to D3 but were subjected to long call hold times, the notice that was sent to customers conveniently left out the fact that their current modems were a bottleneck, there was a fee to install the modem, they had to return the D2 modem or pay an unreturned equipment fee in order to upgrade to D3 modems.
- Programmed D2 routers to cap speeds at 20 Mbps but did not switch the pricing tier to a lower one.
- Rejected recommendation to deploy newer 802.11ac routers for higher speed tiers to save costs.
- Manipulated FCC results, temporarily give more ports to Cogent so as to improve their score.
- League of Legends by Riot games requires low latency and packet loss, both were high (and higher compared to other NY ISPs) before Riot agreed to pay Spectrum.
- Cherry picked other online content besides League to slow down more than others.
The Basic Problem
The Problem
Essentially, Spectrum
was alleged to have used unethical and fraudulent ways to make profits. Now imagine that you just graduated from UB with a bachelor's degree in Computer Engineering/Computer Science and got hired by ForProfitOnly
Internet provider. You're recruited into ForProfitOnly
as a junior software engineer. It's your first day at work and your first assignment/task is to come up with routing algorithms to generate paths that will be used to route packets in ForProfitOnly's
network topology. Since it's your first day at work, you're very eager to please your superiors by delivering as much revenue as possible to ForProfitOnly
. Below is a detailed description of your task and the various problems that you need to solve.
Simplifications galore!
To make the problem more manageable, we have made many simplifying assumptions that at the same time hopefully capture the "essence" of the related fact in real-life. Wherever possible, we will provide more details that we are sweeping under the rug and if necessary provide a reference for further reading.
Notation Table
The project description is a bit notation heavy. If you start losing track, here is the notation page (opens in a new window) that might be useful.
The Graph
You are given an undirected communication graph $G = (V,E)$ of the ForProfitOnly
network, where a designated node $i \in V$ is the content provider (think of a service like Netflix). Every other node $u \in V$ is a router. $C$ is the set of clients and $C \subseteq V \setminus \{i\}$.
Clients vs. Routers
For this project, clients can still route packets but routers cannot be clients.
Every edge $e \in E$ has a delay $d_e$ associated with it, which is the amount of time it takes for a packet of data to traverse through an edge $e \in E$.
$d_e=1$ for all edges $e$
For all the problems, you can assume that for every $e \in E$, $d_e = 1$.
This is a simplification as in real life networks different edges can have different delays. We make this simplification to make the problems in this project easier.
Every client node in $C$ requests a packet of data from the content provider node $i \in V$. The packet addressed to a client $c \in C$ is denoted by $\text{pkt}_c$.
Packets are different
The packets $\text{pkt}_c$ for different clients $c$ are different. I.e. you cannot combine packets for different clients together.
One packet per client
We made the simplifying assumption that there is only one packet per client $c$. Unlike some of the other simplifications we make in this project, this is not such a big simplification.
Routing is centralized
In this project, there is a central algorithm that chooses an $i-c$ path for each client $c$. This is not how routing happens on the Internet. In particular, the TCP/IP protocol is a distributed protocol. However, distributed algorithms are out of the scope of this course.
Let $P$ be any path from the content provider node $i \in V$ to some client node $c \in C$. We define $D(P)$ to be the sum of the delay of all edges in path $P$. That is, $D(P) = \sum_{e \in P} d_e$.
For every client $c\in C$, let $d(c)$ be the minimum of $D(P_c)$ among all $i-c$ paths $P_c$. Let $P'_c$ be the actual $i-c$ path determined by your algorithm for client $c$. As defined above $D(P'_c) = \sum_{e \in P'_c} d_e$.
Every node $u\in V$ has a bandwidth $b_u$, a bound on the number of packets it can send in each time step.
No bound on incoming traffic
Note that we are not putting any restriction on how many packets a router can receive in each time step. We make this simplification so that the problems are a bit simpler.
Routing of packets
Every client $c \in C$ has a priority, which is given by $\text{priority(c)}$.
Larger value is higher priority
$\text{priority(c)}$ is a positive integer and a larger value implies a higher priority.
The content provider node $i$ will send out a packet to all clients simultaneously. This packet will be routed through the path $P'_c$ for each client $c$ that your algorithm outputs.
All packets are sent out of $i$ at the same time
We make the simplifying assumption that packets $\text{pkt}_c$ for all clients $c$ are ready to be routed out of $i$ at the same time. This in real-life is not necessary since different clients might request their packets at different times. Again, this simplification makes the problems easier.
Algorithm Idea
The routing simulator will proceed iteratively, with each iteration mapping directly to a time ‘tick’. Inside each time tick, all the clients are processed and time is advanced only once this processing is finished.
The list of clients, initially maintained as an array (since linked list sorting is slow), will first be sorted by priority, which ensures only the highest priority packets get forwarded if there are bandwidth restrictions. The list is then converted to a Linked List so that as soon as a packet has reached, the client can be removed from the list.
The simulation iterates until all the packets have reached the end of their path. This condition is true when the list of clients is empty.
At each time tick, check if a packet has reached its destination. If it has, remove the client from the list of clients. The client’s delay is set to either the packet delay or infinity depending on whether the packet reached its intended client or not (respectively). Finally, skip to processing the next client.
If the packet is still in transit, its delay is incremented. It is then “forwarded” if the node it is currently at has enough bandwidth and after checking that the corresponding edge is valid. Forwarding comprises incrementing its location by 1 and decrementing the current node’s available bandwidth.
After each time tick, the bandwidth is reset to the router’s $b_u$ value for all routers that participated in the forwarding.
Once we are done processing the entire list, each client’s delay can be retrieved using the corresponding member variable.
Algorithm Details
- Sort list_clients, key = client.priority and in descending order
- Convert list_clients to a Linked List
- active = set()
- While list_clients is not empty:
- For client in list_clients:
- current_node = node that the packet is currently at
- If the client's packet has reached the end of it's path:
- Remove client from list_clients
- Client's delay is set to the packet delay if the current_node is the packet's intended client, otherwise it is set to ∞
- Continue to next iteration
- Increment packet delay
- If current_node's bandwidth > 0:
- If the current node and the next in the packet's path are not neighbors:
- Remove client from list_clients
- Client's delay = ∞
- Continue to next iteration
- Decrement current_node's bandwidth
- Increment packet's current node to the next node in the packet's path
- Add current_node to active
- If the current node and the next in the packet's path are not neighbors:
-
For node in active:
- Set node's bandwidth to node's original bandwidth
- Clear all elements from active
- For client in list_clients:
Payments and Revenue
Every client $c \in C$ makes a payment $\text{pmt}_c$ to ForProfitOnly
and also has a tolerance threshold $\alpha_c$, which represents $c$'s tolerance to slow internet. Please see Problem 1 for a detailed description.
Clients payments can vary
In this project we assume that the payment $\text{pmt}_c$ for different $c$ could be all different (unlike in real-life where typically there are "tiers" of payment).
Example 0
Let's look at a small example graph (please see the figure below) with $11$ nodes. Each node in this graph has a node id which is an integer. In this graph nodes $1,3,6,7,8$ are clients, node $0$ is the ISP node and the remaining nodes $2,4,5,9,10$ are routers. Also, every node's bandwidth is denoted as $b_{\text{<node id>}}$.
Let's say that the clients in this graph have the following payments: $\text{pmt}_1 = \$30, \text{pmt}_3 = \$40, \text{pmt}_6 = \$35, \text{pmt}_7 = \$40, \text{pmt}_8 = \$45$.
$d(c)$ in the above graph $G$
For the graph above, we have $d(1)=2, d(3)=2, d(6)=3, d(7)=4, d(8)=3$.
Below are five problems for you to solve. Problems 1-5 are cumulative. That is they build upon the previous problem and get progressively harder to solve.
Submitting as a group on Autolab
As mentioned above, you will be working on this project as a group. This mean y'all will also submit your solution file as a group. Here is a quick primer on how to form a group on Autolab and to submit as a group (opens in a new page).
The Coding Details
Note
Both the input and output parsers in each of the three languages are already written for you. Note that you have to work with the input data structures provided (which will come pre-loaded with the data from an input file).
Addition is the only change you should make
Irrespective of what language you use, you will have to submit just one file. That file will come pre-populated with some stuff in it. You should not change any of those things because if you do you might break what the grader expects and end up with a zero on the question. You should of course add stuff to it (including helper functions and data structures as you see fit).
Make sure to output valid $i-c$ paths
Make sure that for each client $c$, your code outputs a valid $i-c$ path (including the fact that the first node in the path is $i$ and the last node in the path is $c$). If these conditions are not satisfied, then the grader code will silently set the delay of that path during routing to be $\infty$ (i.e. this error will not be flagged in the Autolab feedback).
Directory Structure
├── src │ ├── ub │ ├── cse │ ├── algo │ ├── util | ├── Pair.java │ ├── Driver.java │ ├── Globals.java │ ├── Graph.java │ ├── Info.java │ ├── MPUtility.java │ ├── Objects.java │ ├── Revenue.java │ ├── Simulator.java │ ├── Solution.java │ ├── Traversals.java │ ├── testcases/ │ ├── input1.txt │ ├── input1.txt-info
You are given eleven coding files: Pair.java
, Driver.java
, Globals.java
, Graph.java
, Info.java
, MPUtility.java
,Objects.java
, Revenue.java
, Simulator.java
, Solution.java
, and Traversals.java
.
Driver.java
implicitly calls methods in MPUtility.java
. MPUtility.java
reads the input files, and encapsulates all the data read from the input file into an Info
object (Info class is in Info.java
). This Info
object is passed on to Solution.java
, and you may access all the data needed from this Info
object. In Solution.java
you should implement the outputPaths()
method which returns a SolutionObject
object, and of course you can add your own data structures in Solution.java
.
Objects.java
has all the necessary object's defined: Client
and Packet
(but you may not have to use this). And Graph.java
is the Graph represented as an adjacency list (HashMap<Integer,ArrayList<Integer>>
).
Please make sure that you take a good look at Info.java
, as it has 11 member variables:
Graph graph
: is the input graph which also includes the ISPArrayList<Client> clients
: is the list ofClient
objects for all client nodes $c \in C$.ArrayList<Integer> bandwidths
: is a mapping between node id's and their corresponding bandwidths. That is, the value of an index, represents the bandwidth of a node whose id is same as the index. Essentially, this is a mapping between each node $u \in V$ and $b_{u}$.HashMap<Integer, Integer> shortestDelays
: is a mapping between client id's and the shortest possible delays to the ISP. (This is only used by the grader and can be safely ignored.)SolutionObject solutionObject
: theSolutionObject
object that will contain your solution returned fromoutputPaths()
(see below for more).float rho1
same as $\rho_{\text{lawsuit}}$float rho2
same as $\rho_{\text{fcc}}$float lawsuit
: same as $A$.float fccFine
: same as $B$.float costBandwidth
: same as $Z$.
Your code will return a SolutionObject
(defined in Objects.java
), which contains a HashMap<Integer, ArrayList<Integer>>
of paths
(make sure your paths start from the content provider); a HashMap<Integer, Integer>
, holding your priorities
for each client and an ArrayList<Integer>
holding your bandwidths
after they have been increased.
Finally, the Solution
class has four instance variables:
info
which is an instance ofInfo
class, and encapsulates all the data read from the input files.graph
which is an instance of theGraph
class the represents the network (note that information is also part ofinfo
and it copied over for your convenience)clients
which is a list ofClient
objects (note that information is also part ofinfo
and it copied over for your convenience)bandwidths
which is a mapping of ids to node bandwidths (note that information is also part ofinfo
and it copied over for your convenience)
Compiling and executing from command line:
Assuming you're in the same directory level as src/
. Run javac src/ub/cse/algo/util/*.java src/ub/cse/algo/*.java to compile.
To execute your code on input1.txt
, run java -cp "src" ub.cse.algo.Driver testcases/input1.txt. The output will be printed to stdout
.
Note
You should not pass input1.txt-info
as a command line argument.
Submission
You only need to submit Solution.java
to Autolab.
You are not provided any output!
There is no output.txt
file for any problem, as it would happen if you were working at ForProfitOnly
.
Simulator.java could be helpful
Simulator.java
contains the code for running the routing simulator as described above. You might find the following methods useful:
/** * Simulate the solution to find the delays to each * Client and return them in a HashMap * * @param graph: Graph Object representing the network * @param clientList: List of Client Objects * @param sol: Solution to Simulate * @return a map of Client IDs to packet delays */ static HashMaprun(Graph graph, ArrayList clientList, SolutionObject sol)
Revenue.java could be helpful
Revenue.java
contains the code for calculating the total revenue as described in the mathematical formulation. You might find the following methods useful:
/** * Static method that will compute the revenue generated from * the given solution given the boolean variables * * @param info: data parsed from the input file * @param solutionObject: the "optimal" solution * @param delays: Map of the delays the packets took to reach the clients * @param pen_1: should the first penalty be applied? * @param pen_2: should the second penalty be applied? * @param updated_bandwidths: have the bandwidths been changed? * @return the calculated revenue */ static float revenue(Info info, SolutionObject solutionObject, HashMapdelays, boolean pen_1, boolean pen_2, boolean updated_bandwidths)
Problem 1
Download Java Skeleton CodeMethod you need to write:
/** * This method must be implemented by you. You may add other methods and subclasses as you see fit, * but they must remain within the Solution class. * @return A SolutionObject object that encapsulates the paths and other data generated by you */ public SolutionObject outputPaths(){ SolutionObject sol = new SolutionObject(); /* TODO: Your solution goes here */ return sol; }
What to Change in the SolutionObject Object?
For this problem you are only required to generate paths for routing packets from the content provider to each client.
This would be represented as a HashMap<Integer,List<Integer>>
, that is the keys of the HashMap<Integer,List<Integer>>
are the client node id's and the corresponding values are the paths (that start from the content provider).
Once you generate this HashMap<Integer,List<Integer>>
of paths, you should set the paths
member of the returned SolutionObject
object equal to the HashMap<Integer,List<Integer>>
generated by you.
You are provided the entire test suite
For the first problem, there is only one testcase on Autolab, which is provided to you.
There is an additional file for this problem
For this problem, take a look at Traversals.java
. This includes code for running BFS that you might find useful.
Do not modify the output!
Please do not change the return statement for any method. For all problems, outputPaths()
method outputs a SolutionObject.
This is an easy problem
Once you understand the problem and get familiar with the template, to get full points you only will need to add a couple of lines of code to Solution.java
.
Problem 2
Download Java Skeleton CodeMethod you need to write:
/** * This method must be implemented by you. You may add other methods and subclasses as you see fit, * but they must remain within the Solution class. * @return A SolutionObject object that encapsulates the paths and other data generated by you */ public SolutionObject outputPaths(){ SolutionObject sol = new SolutionObject(); /* TODO: Your solution goes here */ return sol; }
What to Change in the SolutionObject Object?
For this problem you are only required to generate paths for routing packets from the content provider to each client.
This would be represented as a HashMap<Integer,List<Integer>>
, that is the keys of the HashMap<Integer,List<Integer>>
are the client node id's and the corresponding values are the paths (that start from the content provider).
Once you generate this HashMap<Integer,List<Integer>>
of paths, you should set the paths
member of the returned SolutionObject
object equal to the HashMap<Integer,List<Integer>>
generated by you.
You are provided a subset of the test suite!
For the second problem, there are two testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The second testcase will use the same graph from input1.txt
but with a different info file, input2.txt-info
Do not modify the output!
Please do not change the return statement for any method. For all problems, outputPaths()
method outputs a SolutionObject object.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.java
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 2, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 3
Download Java Skeleton CodeMethod you need to write:
/** * This method must be implemented by you. You may add other methods and subclasses as you see fit, * but they must remain within the Solution class. * @return A SolutionObject object that encapsulates the paths and other data generated by you */ public SolutionObject outputPaths(){ SolutionObject sol = new SolutionObject(); /* TODO: Your solution goes here */ return sol; }
What to Change in the SolutionObject Object?
For this problem you are required to generate paths for routing packets from the content provider to each client.
This would be represented as a HashMap<Integer,List<Integer>>
, that is the keys of the HashMap<Integer,List<Integer>>
are the client node id's and the corresponding values are the paths (that start from the content provider).
Once you generate this HashMap<Integer,List<Integer>>
of paths, you should set the paths
member of the returned SolutionObject
object equal to the HashMap<Integer,List<Integer>>
generated by you.
You should also update the bandwidths as well (if your code does decide to do this). To do so set the bandwidths
member of the returned SolutionObject
object to the updated bandwidths.
You are provided a subset of the test suite!
For the third problem, there are four testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement for any method. For all problems, outputPaths()
method outputs a SolutionObject object.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.java
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 3, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 4
Download Java Skeleton CodeMethod you need to write:
/** * This method must be implemented by you. You may add other methods and subclasses as you see fit, * but they must remain within the Solution class. * @return A SolutionObject object that encapsulates the paths and other data generated by you */ public SolutionObject outputPaths(){ SolutionObject sol = new SolutionObject(); /* TODO: Your solution goes here */ return sol; }
What to Change in the SolutionObject Object?
For this problem you are required to generate paths for routing packets from the content provider to each client.
This would be represented as a HashMap<Integer,List<Integer>>
, that is the keys of the HashMap<Integer,List<Integer>>
are the client node id's and the corresponding values are the paths (that start from the content provider).
Once you generate this HashMap<Integer,List<Integer>>
of paths, you should set the paths
member of the returned SolutionObject
object equal to the HashMap<Integer,List<Integer>>
generated by you.
You should also update the bandwidths/priorties as well (if your code does decide to do this). To do so set the bandwidths
/priorities
member of the returned SolutionObject
object to the updated bandwidths/priorities.
You are provided a subset of the test suite!
For the fourth problem, there are five testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement for any method. For all problems, outputPaths()
method outputs a SolutionObjet object.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.java
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 4, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 5
Download Java Skeleton CodeMethod you need to write:
/** * This method must be implemented by you. You may add other methods and subclasses as you see fit, * but they must remain within the Solution class. * @return A SolutionObject object that encapsulates the paths and other data generated by you */ public SolutionObject outputPaths(){ SolutionObject sol = new SolutionObject(); /* TODO: Your solution goes here */ return sol; }
What to Change in the SolutionObject Object?
For this problem you are required to generate paths for routing packets from the content provider to each client.
This would be represented as a HashMap<Integer,List<Integer>>
, that is the keys of the HashMap<Integer,List<Integer>>
are the client node id's and the corresponding values are the paths (that start from the content provider).
Once you generate this HashMap<Integer,List<Integer>>
of paths, you should set the paths
member of the returned SolutionObject
object equal to the HashMap<Integer,List<Integer>>
generated by you.
You should also update the bandwidths/priorties as well (if your code does decide to do this). To do so set the bandwidths
/priorities
member of the returned SolutionObject
object to the updated bandwidths/priorities.
You are provided a subset of the test suite!
For the fifth problem, there are eight testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement for any method. For all problems, outputPaths()
method outputs a SolutionObject object.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.java
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 5, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Directory Structure
├── Driver.py ├── Enums.py ├── Graph.py ├── LinkedList.py ├── Objects.py ├── Revenue.py ├── Simulator.py ├── Solution.py ├── Traversals.py ├── Utility.py ├── testcases/ │ ├── input1.txt ├── input1.txt-info
You are given ten coding files. Out of these, you can safely ignore Enums.py
and LinkedList.py
. These files are merely required to do some processing in the background. For example, Enums.py
is used in conjunction with the file I/O code. LinkedList.py
is an implementation of a linked list in Python since there is no standard one.
Driver.py
takes the input file, parses it using Utility.py
and calls your Solution.py
class' output_paths()
method on data structures it creates.
The $i-c$ paths output by you (along with, depending on the question, the updated bandwidths and packet priorities) are passed in to the routing simulator inside Simulator.py
, which processes them and determines the routing delay faced by each client.
Finally, these delays are passed into the revenue calculation function inside Revenue.py
. It then prints the revenue you gathered based on your routing decisions. You only need to update the Solution.py
file. You may write your own helper methods and data structures in it.
The Solution
class contains four data structures.
problem
, which simply contains the problem number of the current template as a member variable on the Solution class. You DO NOT need to worry about this variable.isp
which is the ID of the ISP node. Note that this is the same as content provider or $i$ as mentioned in the problem description.graph
which is the input graph $G$ in the adjacency list representation that you are familiar with. The key is a node ID (not client, there are nodes that may not be clients) and the value is the list of nodes it is connected to.info
which is a mapping between a string representing the various input parameters and the corresponding data structure. For example,info["bandwidths"]
lets you access the mapping between node IDs and their bandwidths. More details oninfo
below.
As outlined in the problem descriptions, there are various additional input parameters provided to you besides the graph, which you can use to influence the routing. These are available through the info
data structure available as a member variable of the Solution
class.
The parameters are listed as follows:
list_clients
[list
of client IDs] is a list of all clients in $C$bandwidths
[dict
: node IDs (int
) -> bandwidth (int
)] maps $u\in V$ to $b_u$alphas
[dict
: client IDs (int
) -> alphas (float
)] maps $c\in C$ to $\alpha_c$payments
[dict
: client IDs (int
) -> payments (float
)] maps $c\in C$ to $\text{pmt}_c$betas
[dict
: client IDs (int
) -> betas (float
)] maps $c\in C$ to $\beta_c$is_rural
[dict
: client IDs (int
) -> is_rural ({0, 1}
)] if is_rural[$c$]= 0, then $c\not\in R$ and if =1, then $c\in R$is_fcc
[dict
: client IDs (int
) -> is_fcc ({0, 1}
)] if is_fcc[$c$] =0, then $c\in S$ and if =1, then $c\in S$.rho1
[float
] same as $\rho_{\text{lawsuit}}$rho2
[float
] same as $\rho_{\text{fcc}}$lawsuit
[float
] same as $A$fcc_fine
[float
] same as $B$cost_bandwidth
[float
] same as $Z$
info
data structure. For eg. info["bandwidths"]
is a map from node IDs to their bandwidths, info["lawsuit"]
is a floating point representing the amount of the lawsuit fine and so on. Note that not all parameters are available for each problem, for eg. Problem 1 and Problem 2 only have the first four available for use.
Your method is expected to return a dictionary
indexed by client IDs with their $i$-$c$ path as the value. For problems 3, 4, 5 you also need to return a dictionary
indexed by node IDs with their updated bandwidth as the value. For problems 4 and 5 you further need to return a dictionary
indexed by client IDs with their priorities as the value.
As a reminder if you return an object you are not supposed to, for eg. priorities in problem 2, it will be ignored by the grader.
Executing from command line:
Assuming you're in the same directory level as Driver.py
and you want to run your code on the input1.txt
. Run python Driver.py testcases/input1.txt.
Note
Note that you do not need to pass in input1.txt-info
as a parameter.
Submission
You only need to submit Solution.py
to Autolab.
You are not provided any output!
There is no output.txt
file for any problem, as it would happen if you were working at ForProfitOnly
.
Simulator.py
could be useful
Simulator.py
contains the code for running the routing simulator as described above. You might find the following method useful:
def run(self, graph, isp, list_clients, paths, bandwidths, priorities, is_rural): """ Runs the simulation based on the paths provided by the student """ def get_delays(self, list_clients): """ Returns the delay experienced by each client after the simulation has run its course """
Revenue.py
could be useful
Revenue.py
contains the code for retrieving the revenue obtained as described above. You might find the following methods useful:
def revenue(self, client_list, alphas, betas, optimal_dict, payments, lawsuit, rho_lawsuit, fcc_fine, rho_fcc, is_fcc, pen_1, pen_2, updated_bandwidths, original_bandwidths, update_cost): """ determines overall revenue :param client_list: list of client objects :param alphas: mapping of clients to their alpha values :param betas: mapping of clients to their beta values :param optimal_dict: mapping of clients to their optimal delays :param payments: mapping of clients to their payment values :param lawsuit: lawsuit cost :param rho_lawsuit: lawsuit factor :param rho_fcc: fcc factor :param is_fcc: mapping of nodes to either 0 or 1 :param fcc_fine: fcc penalty :param pen_1: if the lawsuit should be taken into account :param pen_2: if the fcc should be taken into account :param updated_bandwidths mapping of nodes to new bandwidths as set by the solution :param original_bandwidths mapping of nodes to original bandwidths as provided by the problem :param cost to upgrade the bandwidth by 1 :return: the total revenue """
Problem 1
Download Python Skeleton CodeMethod you need to write:
def output_paths(self): """ This method must be filled in by you. You may add other methods and subclasses as you see fit, but they must remain within the Solution class. """ paths, bandwidths, priorities = {}, {}, {} return (paths, bandwidths, priorities)
You are provided the entire test suite
For the first problem, there is only one testcase on Autolab, which is provided to you.
There is an additional file for this problem
For this problem, take a look at Traversals.py
. This includes code for running BFS that you might find useful.
Do not modify the output!
Please do not change the return statement. All the problems return the same tuple, but bandwidths
and priorities
should be set to the empty dictionary for this problem. You need to assign a value to the paths
variable as your solution.
This is an easy problem
Once you understand the problem and get familiar with the template, to get full points you only will need to add up to a couple of lines of code to Solution.py
.
Problem 2
Download Python Skeleton CodeMethod you need to write:
def output_paths(self): """ This method must be filled in by you. You may add other methods and subclasses as you see fit, but they must remain within the Solution class. """ paths, bandwidths, priorities = {}, {}, {} return (paths, bandwidths, priorities)
You are provided a subset of the test suite!
For the second problem, there are two testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The second testcase will use the same graph from input1.txt
but with a different info file, input2.txt-info
Do not modify the output!
Please do not change the return statement. All the problems return the same tuple, but bandwidths
and priorities
should be set to the empty dictionary for this problem. You need to assign a value to the paths
variable as your solution.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.py
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 2, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 3
Download Python Skeleton CodeMethod you need to write:
def output_paths(self): """ This method must be filled in by you. You may add other methods and subclasses as you see fit, but they must remain within the Solution class. """ paths, bandwidths, priorities = {}, {}, {} return (paths, bandwidths, priorities)
You are provided a subset of the test suite!
For the third problem, there are four testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement. All the problems return the same tuple, but priorities
should be set to the empty dictionary for this problem. You need to assign a value to the paths
and bandwidths
variables as your solution.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.py
sets th
e appropriate problem
value. So while you can modify the zip from another problem to work for Problem 3, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 4
Download Python Skeleton CodeMethod you need to write:
def output_paths(self): """ This method must be filled in by you. You may add other methods and subclasses as you see fit, but they must remain within the Solution class. """ paths, bandwidths, priorities = {}, {}, {} return (paths, bandwidths, priorities)
You are provided a subset of the test suite!
For the fourth problem, there are five testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement. All the problems return the same tuple, but in this problem, you need to assign a value to the paths
, bandwidths
and priorities
variables as your solution.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.py
sets th
e appropriate problem
value. So while you can modify the zip from another problem to work for Problem 4, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 5
Download Python Skeleton CodeMethod you need to write:
def output_paths(self): """ This method must be filled in by you. You may add other methods and subclasses as you see fit, but they must remain within the Solution class. """ paths, bandwidths, priorities = {}, {}, {} return (paths, bandwidths, priorities)
You are provided a subset of the test suite!
For the fifth problem, there are eight testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Do not modify the output!
Please do not change the return statement. All the problems return the same tuple, but in this problem, you need to assign a value to the paths
, bandwidths
and priorities
variables as your solution.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.py
sets th
e appropriate problem
value. So while you can modify the zip from another problem to work for Problem 5, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Directory Structure
├── Driver.cpp ├── Solution.cpp ├── Graph.h ├── Objects.h ├── Revenue.cpp ├── Revenue.h ├── Simulator.cpp ├── Simulator.h ├── Traversals.cpp ├── Traversals.h ├── MPUtility.h ├── Utility.h ├── testcases/ │ ├── input1.txt │ ├── input1-info.txt
You are given twelve coding files.
Driver.cpp
takes the input file, parses it, using MPUtility.h
and creates an instance of the class Solution
and calls the outputDistances()
method on it to determine the $i-c$ paths (and possibly bandwidths/ priorities). Then it uses those paths (and priorities/bandwidths where applicable) to run the Simulator.cpp
, which processes them and determines the routing delay faced by each client. Finally these delays are passed into the revenue calculations in Revenue.cpp
. It then prints the revenue you gathered based on your routing decisions. You only need to update the Solution.cpp
file. You may write your own helper methods and data structures in it.
The Solution
class has six member variables:
problem
, which represents the problem number you are working on. You DO NOT need to worry about this variable.graph
which is the input graph. It has aunordered_map
that is the adjacency list representation of $G$, where the keys are the nodes and the values is a vector of its neighbors. There is also anint
,contentProvider
representing the content provider, or $i$.clients
which represents a vector of all clients, or $C$. This will be explained more below.bandwidths
which is a vector that maps $u\in V$ to $b_u$.fines
which is a map that holds the fcc and lawsuit $\rho$ values and fines. The key is either"fcc"
or"lawsuit"
. The values are apair
where the first is the corresponding $\rho$ value and the second is the fine amount (or $A$ and $B$ respectively)band_incr_cost
holds how much it costs to increase a bandwidth by one, or $Z$.
Now for an explanation of the Client
Object (which is in Objects.h
):
id
represents the client's id $c$alpha
is the client $c$'s $\alpha_c$ valuebeta
is the client $c$'s $\beta_c$ valuepayment
is the client $c$'s $pmt_c$ value.is_rural
is set totrue
if $c\in R$, otherwise $c\not\in R$is_fcc
is set totrue
if $c\in S$, otherwise $c\not\in S$priority
is the client's priority.
The output for this function must output a Solution_Object
(defined in Objects.h
), which contains an unordered_map
of <int, vector<int>>
, holding your paths
(make sure all paths start with the content provider); a vector
of <int>
, holding your bandwidths
after they have been increased; and an unordered_map
of <int, int>
, holding your priorities
for each client. Make sure that the order is correct.
Compiling and executing from command line:
Assuming you're in the same directory level as Driver.cpp
. Run g++ -std=c++11 Driver.cpp to compile.
To execute your code on input1.txt
, run ./a.out testcases/input1.txt. Do not worry about passing input1.txt-info
, Driver.cpp
will generate this name for you.
Submission
You only need to submit Solution.cpp
to Autolab.
You are not provided any output!
There is no output.txt
file for any problem.
Simulator.cpp
could be useful!
Simulator.cpp
contains the code for running the simulator as described above. You might find the following method useful:
unordered_map<int, int> Simulator(Graph &g, Solution_Object &sol, const vector<Client> &clients_vec){ /* *Runs the simulator with the graph, list of clients, *determined paths, bandwidths and priorities as the inputs. *It outputs a map of the clients with their delays */ }
Revenue.cpp
could be useful!
Revenue.cpp
contains the code for retrieving the revenue obtained as described above. You might find the following methods useful:
int pen_0(Graph &input, vector<Client> &clients, unordered_map<int, int> &calc_delays, bool count_rural, bool five){ /* *determines whether or not a client will pay their internet fee. */ }
int pen_1(Graph &input, vector<Client> &clients, unordered_map<int, int> &delays, unordered_map<string, pair<float, int>> &fine_info){ /* * Determines whether or not the ISP takes on the FCC and/or Lawsuit fines */ }
int bandwidth_increase(vector<int> &old_bandwidths, vector<int> &new_bandwidths, int increase_amount){ /* * Determines the amount it costs to increase the bandwidths for problems 4 and 5 */ }
Problem 1
Download C++ Skeleton CodeMethod you need to write:
Solution_Object outputPaths() { Solution_Object solution = Solution_Object(); return solution; }
You are provided the entire test suite!
For the first problem, there is only one testcase on Autolab, which is provided to you.
There is an additional file for this problem.
For this problem, take a look at Traversals.cpp
. This includes code for running BFS that you might find useful.
Be careful about your output!
Do not change the bandwidths
or priorities
in your output Solution_Object
. But do change the paths
appropriately.
This is an easy problem
Once you understand the problem and get familiar with the template, to get full points you only will need to add up to a couple of lines of code to Solution.cpp
.
Problem 2
Download C++ Skeleton CodeMethod you need to write:
Solution_Object outputPaths() { Solution_Object solution; /* * TODO: Implement the solution */ return solution; }
You are provided a subset of the test suite!
For the second problem, there are two testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The second testcase will use the same graph from input1.txt
but with a different info file, input2.txt-info
Be careful about your output!
Do not change the bandwidths
or priorities
in your output Solution_Object
. But do change the paths
appropriately.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.cpp
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 2, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 3
Download C++ Skeleton CodeMethod you need to write:
Solution_Object outputPaths() { Solution_Object solution; // change both solution.paths and solution.bandwidths for this problem /* * TODO: Implement the solution */ return solution; }
You are provided a subset of the test suite!
For the second problem, there are four testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Be careful about your output!
Do not change the priorities
in your output Solution_Object
. But do change the paths
and/or bandwidths
appropriately.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.cpp
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 3, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 4
Download C++ Skeleton CodeMethod you need to write:
Solution_Object outputPaths() { Solution_Object solution; // change solution.paths, solution.bandwidths and solution.priorities for this problem /* * TODO: Implement the solution */ return solution; }
You are provided a subset of the test suite!
For the fourth problem, there are five testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Be careful about your output!
Do change the paths
and/or bandwidths
and/or priorities
of solution
appropriately.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.cpp
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 4, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Problem 5
Download C++ Skeleton CodeMethod you need to write:
Solution_Object outputPaths() { Solution_Object solution; // you might have to change all three of // solution.paths, solution.bandwidhts and solution.priorities for this problem /* * TODO: Implement the solution */ return solution; }
You are provided a subset of the test suite!
For the fifth problem, there are eight testcases on Autolab. The first one, input1.txt
in conjunction with input1.txt-info
is provided to you. The other testcases will use the same graph from input1.txt
but with different info files.
Be careful about your output!
Do change the paths
and/or bandwidths
and/or priorities
of solution
appropriately.
What's the difference in the zips?
The templates for the different problem are essentially the same except that Driver.cpp
sets the appropriate problem
value. So while you can modify the zip from another problem to work for Problem 5, to be on the safe side, we still encourage y'all to download the zip for this problem and work on it separately from your work on other problems.
Grading Guidelines
The grading works a little differently for this project.
Each testcase is worth 5 points. The number of testcases for each problem depends on the maximum points ($max\_points$) achievable, and is equal to $\frac{max\_points}{5}$. For eg. Problem 1 has one testcase, since it is worth 5 points, Problem 2 has two testcases, since it is worth 10 points and so on.
For Problem 1, you get the full 5 points if your revenue matches ours and 0 otherwise.
Except for Problem 1, there is partial grading for each testcase. The number of points awarded to you depend on how well your solution's revenue compares with our revenue.
For other problems, the thresholds are outlined below, the numbers on the left indicate the ratio of (your solution's revenue - revenue of optimal Solution for Problem 1) and (our revenue - revenue from optimal Solution for Problem 1) in percentage, and the right half indicates the points achieving that ratio will award you.
- $[100, 80]$ -> 5 points
- $[80, 60)$ -> 4 points
- $[60, 40)$ -> 3 points
- $[40, 20)$ -> 2 points
- $[20, 5)$ -> 1 points
- $[0, 5]$ -> 0 points