Logic code of AMPL about TSPTW - ampl

I am studing this AMPL code (TSPTW: https://github.com/inter0509/TSPTW).
It is a code to resolve a TSP with Time Window (I hope...)
rank: binary-matrix (2x2) -> if rank[i,j]==1, then take that arc from "node-i" to "node-j"
constrain11 : only one arc into the node
constrain12 only one arc from the node
constrain13: must select arc to node-0 to node-0
constrain21: Why is there that piece of code ("+sum{i in V,j in V:i!=j}(c[i,j])*y[i,k-1,j,k];")?
constrain31/32/33: I have no idea..
constrain4: you must arrive after sum{j in V}(r[j]*rank[j,k]);
constarin5: you don't left node before sum{j in V}(d[j]*rank[j,k]);
"r": hour when you arrive
"d": hour when you leave the node
"p": hours you must stop in the node.
Is it correct? I think no...

It's a bit painful trying to interpret uncommented code with uninformative variable names, but I think I've figured it out.
In the previous tsp.mod presented at the same place, there's a binary decision variable x{V,V} which has x[i,j] = 1 if and only if the path goes from node i to node j.
In tsptw.mod there is a binary decision variable rank{V,V}, so we might expect it to work the same way as x{V,V} in the previous model, but it doesn't.
Instead, rank[j,k] = 1 if and only if node j is the k'th city to be visited in the salesman's tour. For instance, if rank[8,3] = rank[5,4] = rank [12,5] = 1, then the third city in the tour is city #8, the fourth is city #5, the fifth is city #12, and so on.
Cities are numbered from 0 to n, so there are actually n+1 cities in this problem.
The decision variable start[j] means "start time of the j'th city in the tour ordering": e.g. if rank[8,3] = 1, then start[3] gives the time at which we start in city #8. (The counting starts at 0 for the start city.)
r and d represent the earliest start time and latest finish time permitted for each city (indexed on the cities' numeric ID, and NOT on their order in the tour). p represents the time required to stay within each city, again indexed on the city's numeric ID.
c[j,k] is the time taken to travel from city j to city k.
y[i,k-1,j,k] equals 1 if the k-1'th city in the tour is city i, and the k'th city is j. (Enforced by constraints 31-33.)
Breaking down the objective function:
minimize total_time : start[n]+sum{j in V:j!=0}(c[j,0]*rank[j,n])
+sum{j in V:j!=0} (p[j]*rank[j,n]);
start[n] : this is just the start time for the n'th (last) city in the tour.
sum{j in V:j!=0}(c[j,0]*rank[j,n]) : rank[j,n] = 1 if and only if city with ID #j is the n'th city in the tour, 0 otherwise. c[j,0] is the time to travel from that city to city #0 (the start). So this gives the travel time from the n'th (last) city to return to where we started.
sum{j in V:j!=0} (p[j]*rank[j,n]) : this is the time required to spend at the n'th city.
Working through the constraints:
subject to constrain11 {j in V}: sum{k in V} rank[j,k]=1;
subject to constrain12 {k in V}: sum{j in V} rank[j,k]=1;
Each city must have one and only one rank (position in the tour). For each rank, there must be exactly one city assigned to that rank. (These two are actually redundant, but that doesn't matter.)
subject to constrain13: rank[0,0] = 1;
We start at city 0.
subject to constrain21 {k in V2}: start[k] >=
start[k-1] + sum{i in V}(p[i]*rank[i,k-1])
+sum{i in V,j in V:i!=j}(c[i,j])*y[i,k-1,j,k];
The time at which we start in the k'th city on our route must be no less than the start time for the previous city, plus the time we needed to spend in that previous city, plus the cost of travelling between the k-1'th and k'th cities.
subject to constrain22: start[0] = 0;
Start the trip at time zero.
subject to constrain31 {i in V,j in V,k in V2}: y[i,k-1,j,k]<=rank[i,k-1];
subject to constrain32 {i in V,j in V,k in V2}: y[i,k-1,j,k]<=rank[j,k];
subject to constrain33 {i in V,j in V,k in V2}: y[i,k-1,j,k]>=rank[i,k-1]+rank[j,k]-1;
Collectively, these ensure that y[i,k-1,j,k] is 1 if the k-1'th city visited is i, and the k'th city visited is j, and otherwise it is zero.
Note: although y is indexed on {V,V,V,V2}, most of those indices are actually irrelevant; only the ones where the second index is one less than the fourth index have any significance to the problem.
subject to constrain4 {k in V2}: start[k] >= sum{j in V}(r[j]*rank[j,k]);
The time at which we start the k'th city of the tour must be greater than or equal to the earliest start time (r) for whatever the k'th city actually is (j such that rank[j,k] = 1).
subject to constarin5 {k in V2}: start[k]+sum{j in V}(p[j]*rank[j,k])
<= sum{j in V}(d[j]*rank[j,k]);
The time at which we start the k'th city, plus the time (p) required for that city, must not exceed the latest finish time (d) for that city.
I haven't gone looking for bugs, so I won't vouch for its correctness, but I think the general approach makes sense under that interpretation.
If you found this answer helpful, please pay it forward by promising always to comment your code and use informative variable names ;-)

Related

Product of binary and integer constraint - Linear Programming

I am trying to formulate a linear program that will assign different number of employees to start in different days. Each group of employees starting on a day will get two days off during the week. However, the schedule is unknown. For example, employees starting Monday can be off any two days in the week. Since the number that will start on day (i) is unknown and whether they will have a day off or not is unknown, I will have the product of two decision variables - one is an integer xi (employees starting on day i) and a binary variable yij (whether the employees starting on day i have a day off on day j).
I am done with formulation and here it is:
Decision variables 1: xi (employees starting on day i)
Decision variables 2: yij (1 if employees starting on day i are working on day j, or 0 if employees starting on day i are off on day j)
Objective function:
Minimize total employees-- sum (i in 1..7) xi
Subject to:
xi*yij >= Requiredj (the number of available workers on day j have to satisfy the demand on day j)
I am trying to code this on CPLEX but i dont know how to make xi*yij linear and write the code....can anyone please help me?
Thank you.
In How to with OPL How to multiply a decision variable by a boolean decision variable in CPLEX ?
// suppose we want b * x <= 7
dvar int x in 2..10;
dvar boolean b;
dvar int bx;
maximize x;
subject to
{
// Linearization
bx<=7;
2*b<=bx;
bx<=10*b;
bx<=x-2*(1-b);
bx>=x-10*(1-b);
// if we use CP we could write directly
// b*x<=7
// or rely on logical constraints within CPLEX
// (b==1) => (bx==x);
// (b==0) => (bx==0);
}

Is this O(N) algorithm actually O(logN)?

I have an integer, N.
I denote f[i] = number of appearances of the digit i in N.
Now, I have the following algorithm.
FOR i = 0 TO 9
FOR j = 1 TO f[i]
k = k*10 + i;
My teacher said this is O(N). It seems to me more like a O(logN) algorithm.
Am I missing something?
I think that you and your teacher are saying the same thing but it gets confused because the integer you are using is named N but it is also common to refer to an algorithm that is linear in the size of its input as O(N). N is getting overloaded as the specific name and the generic figure of speech.
Suppose we say instead that your number is Z and its digits are counted in the array d and then their frequencies are in f. For example, we could have:
Z = 12321
d = [1,2,3,2,1]
f = [0,2,2,1,0,0,0,0,0,0]
Then the cost of going through all the digits in d and computing the count for each will be O( size(d) ) = O( log (Z) ). This is basically what your second loop is doing in reverse, it's executing one time for each occurence of each digits. So you are right that there is something logarithmic going on here -- the number of digits of Z is logarithmic in the size of Z. But your teacher is also right that there is something linear going on here -- counting those digits is linear in the number of digits.
The time complexity of an algorithm is generally measured as a function of the input size. Your algorithm doesn't take N as an input; the input seems to be the array f. There is another variable named k which your code doesn't declare, but I assume that's an oversight and you meant to initialise e.g. k = 0 before the first loop, so that k is not an input to the algorithm.
The outer loop runs 10 times, and the inner loop runs f[i] times for each i. Therefore the total number of iterations of the inner loop equals the sum of the numbers in the array f. So the complexity could be written as O(sum(f)) or O(Σf) where Σ is the mathematical symbol for summation.
Since you defined that N is an integer which f counts the digits of, it is in fact possible to prove that O(Σf) is the same thing as O(log N), so long as N must be a positive integer. This is because Σf equals how many digits the number N has, which is approximately (log N) / (log 10). So by your definition of N, you are correct.
My guess is that your teacher disagrees with you because they think N means something else. If your teacher defines N = Σf then the complexity would be O(N). Or perhaps your teacher made a genuine mistake; that is not impossible. But the first thing to do is make sure you agree on the meaning of N.
I find your explanation a bit confusing, but lets assume N = 9075936782959 is an integer. Then O(N) doesn't really make sense. O(length of N) makes more sense. I'll use n for the length of N.
Then f(i) = iterate over each number in N and sum to find how many times i is in N, that makes O(f(i)) = n (it's linear). I'm assuming f(i) is a function, not an array.
Your algorithm loops at most:
10 times (first loop)
0 to n times, but the total is n (the sum of f(i) for all digits must be n)
It's tempting to say that algorithm is then O(algo) = 10 + n*f(i) = n^2 (removing the constant), but f(i) is only calculated 10 times, each time the second loops is entered, so O(algo) = 10 + n + 10*f(i) = 10 + 11n = n. If f(i) is an array, it's constant time.
I'm sure I didn't see the problem the same way as you. I'm still a little confused about the definition in your question. How did you come up with log(n)?

AMPL: Modeling vehicles to departure "every n hours"

I want to model that departures from a node can only take place in a "every n hours" manner. I've started to model this using two variables - starttime[i,j,k] shows when vehicle k departured i with j as destination, x[i,j,k] is a binary variable having value 1 if vehicle k drove from i to j, and 0 otherwise. The model is:
maximize maxdrive: sum{i in V, j in V, k in K} traveltime[i,j]*x[i,j,k];
subject to TimeConstraint {k in K}:
sum{i in V, j in V} (traveltime[i,j]+servicetime[i])*x [i,j,k] <= 1440;
subject to StartTime{i in V,j in V, k in K}:
starttime[i,j,k] + traveltime[i,j] - 9000 * (1 - x[i,j,k]) <= starttime[j,i,k];
subject to yvar{i in V, j in V}:
sum{k in K} x[i,j,k] <= maxVisits[i,j];
subject to Constraint1{i in V, j in V, k in K, g in V, h in K}:
starttime[i,j,k] + TimeInterval[i]*x[i,j,k] <= starttime[i,g,h];
The constraint in question is "Constraint1" where i is the origin node, j the destination node, and k is the vehicle. The index g is used to show that the later departure can be to any destination node. TimeInterval corresponds to the interval intended, i.e. if TimeInterval at i is 2 hours, the starttime of the next vehicle to departure from i must not be less than 2 hours from previous departure. The origins corresponds to specific products (only available from said origin node) whereas I want the vehicles to not be bounded to a specific origin node - they should be able to jump between nodes to utilize backhauling etc. In other words, I want to conduct this constraint without having restraints on the vehicles themselves but rather the origin nodes.
The objective function to "maximize the traveltime" may seem strange, but the objective function is rather obsolete really. If the constraints are met, the solution is adequate. To maximize traveltime is merely an attempt to "force" the x variables to become 1.
The question is: how can I do this? With this formulation, all x[i,j,k] variables dissappears from the answer (without this constraint, some of the binary variables x becomes 1 and the other 0. The solution meets the maxVisits requirement. With the constraint all x variables becomes 0 and all starttimes becomes 0 as well. MINTO (The solver) doesn't state that the problem is infeasible either.
Also, how to separate the vehicles so the program recognizes that it is a comparison between all departures? I would rather to not include time dimensions, at it would give so much more variables.
EDIT: After trying a new model using a non-linear solver I've seen some strange results. Specifically, I'm using the limit 1440 (minutes) as an upper bound as to for how long a vehicle can operate each day. Using this model below the solution is 0 for every variable, but the starttime for all combinations of i,j,k is 720 (half of 1440). Does anyone have any clue in regards of what causing this solution? How did this constraint remove the link between starttime being higher than 0 requiring that x must be 1.
subject to StartTimeSelf{i in V, j in V, k in K, g in K, h in V}:
starttime[i,j,k]*x[i,j,k] + TimeInterval[i]*x[i,j,k] + y[i,k] <= starttime[i,h,g]*x[i,j,k];

AMPL: Model terminals within a destination city

I've encountered a problem which I have not found any solution to reading the AMPL documentation of sets.
What I want to model is that a city, say Kir, must have for instance 9 deliveries from another city, for instance Sto. However, these deliveries must arrive in Kir at some specific terminals, each terminal being open only for a small amount of time (approx 2 minutes) each day. The same must be true for the origin node. The route from Sto must be specified from a specific terminal (so the path can be "followed" in the results).
I've started to model using the "set V within K" operation for sets, but that requires that V must be the same set, or a subset of K where K is the set representing the "nodes" - Kir, Sto and so on and V is the set of names of the terminals "Terminal1", "Terminal2" etc.
I've started to check for instance "set K dimension 4" defined as for instance:
set K dimension 4;
data;
set K:=
Sto Kir Terminal1 Terminal2
Bod Kir Terminal3 Terminal2;
Where set K represents from which city (for example Sto) a delivery should be driven (to for example Kir), where the departing terminal in Sto is Terminal1 and the delivering terminal in Kir is Terminal2. This has the downside of having to specifiy a large number of combinations (there are approximately 22 terminals in Kir alone etc) manually. I don't know how to model the constraints then either. For instance the "one dimension" set I've previously had:
subject to yvar{i in V, j in V}:
sum{k in H} x[i,j,k] <= maxVisits[i,j];
where V is the set of cities alone, and H is the set of vehicles, maxVisits represents the maximum amount of deliviries from city i to city j and x is 1 if a delivery is made from i to j using vehicle k. I don't understand how this could be modeled, using the four dimensional set K.
Regards,
One way to model this is to index x over K and H and change the summation to include terminals:
var x{K, H} binary;
subject to yvar{i in V, j in V}:
sum{(i,j,t,u) in K, k in H} x[i,j,t,u,k] <= maxVisits[i,j];
The indexing (i,j,t,u) in K in the summation will iterate over pairs of terminals that are endpoints of routes from city i to city j. Note that i and j are fixed here because they are defined in the constraint indexing {i in V, j in V}.

Minimum number of states needed?

Definition of a language L with alphabet { a } is given as following
L = { ank | k > 0 ; and n is a positive integer constant }
What is the number of states needed in a DFA to recognize L?
In my opinion it should be k+1 but I am not sure.
The language L can be recognized by a DFA with n+1 states.
Observe that the length of any string in L is congruent to 0 mod n.
Label n of the states with integers 0, 1, 2, ... n-1, representing each possible remainder. An additional state, S, is the start state. S has a single transition, to state 1. If the machine is currently in state i, on input it moves to state (i+1) mod n. State 0 is
the only accepting state. (If the empty string were part of L, we could eliminate S and make state 0 the start state).
Suppose there were a DFA with fewer than n+1 states that still recognized L. Consider the sequence of states S0, S1, ... Sn encountered while processing the string an. Sn must be an accepting state, since an is in L. But since there are fewer than n+1 distinct states in this DFA, by the pigeonhole principle there must have been some state that was visited at least twice. Removing that loop gives another path (and another accepted string), with length < n, from S0 to Sn. But L contains no strings shorter than n, contradicting our assumption. Therefore no DFA with fewer than n+1 states recognizes L.