Mathematical modeling from gurobipy to pyomo: How to enumerate over a set in pyomo? - set

I implemented a course planning problem in gurobipy. It all works well. My next task is to rewrite it in pyomo. I had difficulties with one specific equation (written in gurobipy):
model.addConstrs((quicksum(gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau < len(T))
>= dur[m] * start[l, k, s, t] for index_t, t in enumerate(T) for m in M
for k in KM[m] for l in LM[m] for s in SM[m]), name='Hintereinander')
gamma[lkst] and start[lkst] are binary decision variables. l,k,s,t are indices where t are periods. So the set T is a list of the periods i have. Here in this equation i need the ord(t) to be able to do the calculations in the sum. Therefore I perform an enumeration(T) at the end of the euqation.(When looping over all needed indices).
My data is given beforehand, so i formulate a ConcreteModel() in pyomo. I have difficulties in including the enumeration of the Set T in pyomo.
What I already have:
def gamma_hintereinander_rule(model,m,k,l,s):
for index_t,t in enumerate(T):
if k in KM[m]:
if l in LM[m]:
if s in SM[m]:
return sum(model.gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau< len(T)) >= dur[m] * model.start[l, k, s, t]
else:
return Constraint.Skip
else:
return Constraint.Skip
else:
return Constraint.Skip
model.gamma_hintereinander = Constraint(M, K, L, S,rule=gamma_hintereinander_rule)
It doesn't work correctly.
I'd be really happy and thankful if someone could help me!
Best regards!
Zeineb

The problem is the for-loop inside of the constraint rule. You are exiting the rule after the first return statement is encountered and so only 1 constraint or Constraint.Skip is returned despite the for-loop. I think the best approach is to index your Constraint by T something like:
def gamma_hintereinander_rule(model,m,k,l,s,t):
index_t = T.index(t)
if k in KM[m]:
if l in LM[m]:
if s in SM[m]:
return sum(model.gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau< len(T)) >= dur[m] * model.start[l, k, s, t]
else:
return Constraint.Skip
else:
return Constraint.Skip
else:
return Constraint.Skip
model.gamma_hintereinander = Constraint(M, K, L, S, T, rule=gamma_hintereinander_rule)

Related

Is there a log(n) algorithm for changing a lines list to a point list?

i have a list of lines represented in (pointA, pointB) formatted which is not sorted yet, like: (A, B),(C, D), (B, F), (F,C)
so far i wanna change it to a point list as: A, B, F, C, D, A
by the way, all point in lines can be retrieved.
Tks
With a hashmap that has a O(1) amortised average time complexity for insertion and lookup, you can do it in O(n) in a trivial way.
that's exactly what i need!
suppose i have seven line: (A, B), (A, C), (D, B), (D, E), (F, G), (F, E), (G, H), (C, H) and i convert it to A-》B-》D-》E-》F—》G-》H-》C
using hash can solve the problem quickly:
def point_to_hash(point):
return str(point[0]) +','+ str(point[1])
left_hash = point_to_hash(convex_hull_lines[0][0])
points_dict = {left_hash: convex_hull_lines[0][1]}
right_hashes = [point_to_hash(convex_hull_lines[0][1])]
for line in convex_hull_lines[1:]:
if point_to_hash(line[0]) in points_dict.keys() or point_to_hash(line[1]) in right_hashes:
points_dict[point_to_hash(line[1])] = line[0]
right_hashes.append(point_to_hash(line[0]))
else:
points_dict[point_to_hash(line[0])] = line[1]
right_hashes.append(point_to_hash(line[1]))
convex_hull_points = [convex_hull_lines[0][0], convex_hull_lines[0][1]]
point_hash = point_to_hash(convex_hull_points[1])
step = 1
step_count = len(points_dict)
while step < step_count:
next_point = points_dict[point_hash]
convex_hull_points.append(next_point)
point_hash = point_to_hash(next_point)
step += 1

Algorithm to precisely compare two exponentiations for very large integers (order of 1 billion)

We want to compare a^b to c^d, and tell if the first is smaller, greater, or equal (where ^ denotes exponentiation).
Obviously, for very large numbers, we cannot explicitely compute these values.
The most common approach in this situation is to apply log on both sides and compare b * log(a) to d * log(c). The issue here is that logs are floating-point operations, and as such we cannot trust our answer with 100% confidence (there might be some values which are incredibly close, and because of floating-point error we get a wrong answer).
Is there an algorithm for solving this problem? I've been scouring the intrernet for this, but I can only find solutions which work for particular cases only (e.g. in which one exponent is a multiple of another), or which use floating point in some way (logarithms, division) etc.
This is sort of two questions in one:
Are they equal?
If not, which one is greater?
As Peter O. observes, it's easiest to build in a language that provides an arbitrary-precision fraction type. I'll use Python 3.
Let's assume without loss of generality that a ≤ c (swap if necessary) and b is relatively prime to d (divide both by the greatest common divisor).
To get at the core of the question, I'm going to assume that a, c > 0 and b, d ≥ 0. Removing this assumption is tedious but not difficult.
Equality test
There are some easy cases where a = 1 or b = 0 or c = 1 or d = 0.
Separately, necessary conditions for a^b = c^d are
i. b ≥ d, since otherwise b < d, which together with a ≤ c implies a^b < c^d;
ii. a is a divisor of c, since we know from (i) that a^b = c^d is a divisor of c^b = c^(b−d) c^d.
When these conditions hold, we can divide through by a^d to reduce the problem to testing whether a^(b−d) = (c/a)^d.
In Python 3:
def equal_powers(a, b, c, d):
while True:
lhs_is_one = a == 1 or b == 0
rhs_is_one = c == 1 or d == 0
if lhs_is_one or rhs_is_one:
return lhs_is_one and rhs_is_one
if a > c:
a, b, c, d = c, d, a, b
if b < d:
return False
q, r = divmod(c, a)
if r != 0:
return False
b -= d
c = q
def test_equal_powers():
for a in range(1, 25):
for b in range(25):
for c in range(1, 25):
for d in range(25):
assert equal_powers(a, b, c, d) == (a ** b == c ** d)
test_equal_powers()
Inequality test
Once we've established that the two quantities are not equal, it's time to figure out which one is greater. (Without the equality test, the code here could run forever.)
If you're doing this for real, you should consult an actual reference on computing elementary functions. I'm just going to try to do the simplest thing that works.
Time for a calculus refresher. We have the Taylor series
−log x = (1−x) + (1−x)^2/2 + (1−x)^3/3 + (1−x)^4/4 + ...
To get a lower bound, truncate the series. To get an upper bound, we can truncate but replace the final term (1−x)^n/n with (1−x)^n/n (1/x), since
(1−x)^n/n (1/x)
= (1−x)^n/n (1 + (1−x) + (1−x)^2 + ...)
= (1−x)^n/n + (1−x)^(n+1)/n + (1−x)^(n+2)/n + ...
> (1−x)^n/n + (1−x)^(n+1)/(n+1) + (1−x)^(n+2)/(n+2) + ...
To get a good convergence rate, we're going to want 0.5 ≤ x < 1, which we can achieve by dividing x by a power of two.
In Python, we'll represent a real number as an infinite generator of shrinking intervals that contain the true value. Once the intervals for b log a and d log c are disjoint, we can determine how they compare.
import fractions
def minus(x, y):
while True:
x_lo, x_hi = next(x)
y_lo, y_hi = next(y)
yield x_lo - y_hi, x_hi - y_lo
def times(b, x):
for lo, hi in x:
yield b * lo, b * hi
def restricted_log(a):
series = 0
n = 0
numerator = 1
while True:
n += 1
numerator *= 1 - a
series += fractions.Fraction(numerator, n)
yield -(series + fractions.Fraction(numerator * (1 - a), (n + 1) * a)), -series
def log(a):
n = 0
while a >= 1:
a = fractions.Fraction(a, 2)
n += 1
return minus(restricted_log(a), times(n, restricted_log(fractions.Fraction(1, 2))))
def less_powers(a, b, c, d):
lhs = times(b, log(a))
rhs = times(d, log(c))
while True:
lhs_lo, lhs_hi = next(lhs)
rhs_lo, rhs_hi = next(rhs)
if lhs_hi < rhs_lo:
return True
if rhs_hi < lhs_lo:
return False
def test_less_powers():
for a in range(1, 10):
for b in range(10):
for c in range(1, 10):
for d in range(10):
if a ** b != c ** d:
assert less_powers(a, b, c, d) == (a ** b < c ** d)
test_less_powers()

Solving a recursive method

I have three variables
Group-Set of Persons ex: {{David, Sebastian, Yousef}, {Boris, Mark}}
Person-Set ex: {David, Mark, Sebastian, Boris, Yousef}
Relation-Set ex: {{David, Mark}, {Sebastian, Boris}}
A Group-Set cannot have any person that are friends with each other.
A Group-Set cannot have duplicates.
I need to create a divide method thats called
divide(person-set, relation-set) and returns a group-set as the example above.
It needs to be solved recursively and loops are not allowed.
I already have a method called areFriends(Person, Person) that returns a boolean if they are friends or not.
This is what I got so far:
divide(ps, r){
divide(ps, r, gs){
let p1 = getRandom(ps);
p2 = getRandom(ps);
if(areFriends(p1, p2) = false){
gs.add(p1);
gs.add(p2);
}
remove(p1, ps);
if(getRandom(ps) != 0){
divide(ps, r, gs);
}
}
I've been dealing with this problem for a long time now and really need help with it. Thanks!
Based on a new constraint (without no loop constraint), we need an indicator (g_ind) for considering groups in the function:
divide(ps, r, g = [[]], g_ind = 0)
p <- empty
if there is any person in ps:
p <- take the first person from ps
else:
return
if g_ind >= len(g):
// all current divisions in g have a friend of p
g.add([p]) // add a new division with initial member p
remove p from ps
divide(ps, r, g, 0)
return
else if any friends of p in r exists in g[g_ind]:
divide(ps, r, g, ++g_ind)
return
else:
g[g_ind].add(p)
remove p from ps
divide(ps, r, g, 0)
return

Finding size of 'shortest range of indices' which lookup all unique path is passed

Given an array of String, Finding the size of 'shortest range of indices' which lookup all unique path is passed.
Example, A = { E, R, E, R, A, R, T, A }, it should be 5. As we can see, ranges of A[2] = E and A[6] = T contains all unique path. (In this case, E, R, A, T)
I can solved with multiple loop like below. (solved by Kotlin.)
fun problem(array: Array<String>): Int {
if (array.isEmpty()) return 0
val unique = array.distinct()
var result = 200000
for (i in 0 until A.size) {
val tempSet = HashSet<String>()
val remaining = A.sliceArray(i until array.size)
var count = 0
while (true) {
tempSet.add(remaining[count])
if (unique.size == tempSet.size) break
count++
if (count == remaining.size) {
count = 200000
break
}
}
result = Math.min(result, count + 1)
}
return result
}
But when a large array (about 100,000) comes in, I don't know how to reduce the time. How can i do?
Some Test case:
[E, R, E, R, A, R, T, A] -> 5. Because [2..6] contains all unique path. (E, R, A, T)
[C, A, A, R, C, A, A, R] -> 3. Because [3..5] contains all unique path. (C, A, R)
[R, T, A, R, A, R, E, R] -> 6. Because [1..6] contains all unique path. (T, A, R, E)
[A, R, R, C, T, E, A, R] -> 5. Because [2..6] contains all unique path. (R, C, T, E, A)
This problem might be effectively solved with "two-pointers" approach.
Make dictionary structure containing char as key and counter as value (in the simplest case - array of int)
Set two indexes L and R in 0.
Move R right, for current char increment counter of corresponding dict element.
When dict size (in case of array - number of non-zero elements) becomes equal to unique , stop
Now move L right, for current char decrement counter of corresponding dict element, removing element when counter becomes zero. When dict size becomes smaller than unique, stop. At the last step L..R interval contains all possible items.
Continue with R and so on
Choose the shortest interval during scanning.
Python code for alike question here
The phrase "all unique path" I will interpret to mean "all possible values".
For a string of length n with k unique values this is solvable in time O(n log(k)) using both a dictionary and a priority queue. The key ideas are this:
On a first pass, find all possible values.
The second time around, keep a dictionary most_recently_found of where each value was most recently found.
Keep a priority queue longest_since of which value it has been the longest since it has been found.
Keep a running minimum of the shortest gap.
And now when you go back through and have found all the values, you follow per iteration logic that looks something like this:
most_recently_found[current_value] = current_position
oldest = longest_since.top()
if current_value == oldest.value:
while oldest.position() != most_recently_found[oldest.position()]:
longest_since.pop()
longest_since.push({value: top.value, position: most_recently_found[oldest.position()]
oldest = longest_since.top()
if current_position - oldest.position() < best_gap:
best_gap = current_position - oldest.position()
The point being that for each value found, you have to update the dictionary (O(1)), might have to take it off the priority queue (O(k)), might have to put something new on the priority queue (O(k)) and might have to do some arithmetic (O(1)). Hence O(n log(k)) for everything.

Optimize a recursive function in Julia

I wrote a Julia code which computes integrals over Gaussian functions and I have a sort-of kernel function which is called over and over again.
According to the Julia built-in Profile Module, this is where I spend most of the time during the actual computation and therefore I would like to see if there is any way in which I can improve it.
It is a recursive function and I implemented it in a kind of straightforward way. As I am not that much used to recursive functions, maybe somebody out there has some ideas/suggestions on how to improve it (both from a purely theoretical algorithmic point of view and/or exploiting special optimizations from the JIT compiler).
Here you have it:
"""Returns the integral of an Hermite Gaussian divided by the Coulomb operator."""
function Rtuv{T<:Real}(t::Int, u::Int, v::Int, n::Int, p::Real, RPC::Vector{T})
if t == u == v == 0
return (-2.0*p)^n * boys(n,p*norm(RPC)^2)
elseif u == v == 0
if t > 1
return (t-1)*Rtuv(t-2, u, v, n+1, p, RPC) +
RPC[1]*Rtuv(t-1, u, v, n+1, p, RPC)
else
return RPC[1]*Rtuv(t-1, u, v, n+1, p, RPC)
end
elseif v == 0
if u > 1
return (u-1)*Rtuv(t, u-2, v, n+1, p, RPC) +
RPC[2]*Rtuv(t, u-1, v, n+1, p, RPC)
else
return RPC[2]*Rtuv(t, u-1, v, n+1, p ,RPC)
end
else
if v > 1
return (v-1)*Rtuv(t, u, v-2, n+1, p, RPC)
RPC[3]*Rtuv(t, u, v-1, n+1, p, RPC)
else
return RPC[3]*Rtuv(t, u, v-1, n+1, p, RPC)
end
end
end
Don't pay that much attention to the function boys, since according to the profiler it is not that heavy.
Just to give an idea of the range of numbers: usually the first call comes from t+u+v ranging from 0 to 3, while n always starts at 0.
Cheers
EDIT -- New information
The generated version is slower for small values of t,u,v, I believe the reason is because expressions are not optimzied by the compiler.
I was benchmarking badly for this case, without interpolating the argument passed. By doing it properly I am always faster with the approach explained in the accepted answer, so hurray!
More generally, does the compiler identify trivial cases such as multiplication by zeros and ones and optimize those away?
Answer to myself: from a quick checking of simple code with #code_llvm it seems not to be the case.
Maybe this works in your case: you can "memoize" whole compiled methods using generated functions and get rid of all recursion after the first call.
Since t, u, and v will stay small, you could generate the fully expanded code for the recursions. Assume for the simplicity a bogus implementation of
boys(n::Int, x::Real) = n + x
Then
function Rtuv_expr(t::Int, u::Int, v::Int, n, p, RPC)
ninc = :($n + 1)
if t == u == v == 0
:((-2.0 * $p)^$n * boys($n, $p * norm($RPC)^2))
elseif u == v == 0
if t > 1
:($(t-1) * $(Rtuv_expr(t-2, u, v, ninc, p, RPC)) +
$RPC[1] * $(Rtuv_expr(t-1, u, v, ninc, p, RPC)))
else
:($RPC[1] * $(Rtuv_expr(t-1, u, v, ninc, p, RPC)))
end
elseif v == 0
if u > 1
:($(u-1) * $(Rtuv_expr(t, u-2, v, ninc, p, RPC)) +
$RPC[2] * $(Rtuv_expr(t, u-1, v, ninc, p, RPC)))
else
:($RPC[2] * $(Rtuv_expr(t, u-1, v, ninc, p, RPC)))
end
else
if v > 1
:($(v-1) * $(Rtuv_expr(t, u, v-2, ninc, p, RPC)) +
$RPC[3] * $(Rtuv_expr(t, u, v-1, ninc, p, RPC)))
else
:($RPC[3] * $(Rtuv_expr(t, u, v-1, ninc, p, RPC)))
end
end
end
will generate you fully expanded expressions like this:
julia> Rtuv_expr(1, 2, 1, 0, 0.1, rand(3))
:(([0.868194, 0.928591, 0.295344])[3] * (1 * (([0.868194, 0.928591, 0.295344])[1] * ((-2.0 * 0.1) ^ (((0 + 1) + 1) + 1) * boys(((0 + 1) + 1) + 1, 0.1 * norm([0.868194, 0.928591, 0.295344]) ^ 2))) + ([0.868194, 0.928591, 0.295344])[2] * (([0.868194, 0.928591, 0.295344])[2] * (([0.868194, 0.928591, 0.295344])[1] * ((-2.0 * 0.1) ^ ((((0 + 1) + 1) + 1) + 1) * boys((((0 + 1) + 1) + 1) + 1, 0.1 * norm([0.868194, 0.928591, 0.295344]) ^ 2))))))
We can stuff that into a generated function Rtuv taking Val types. For each different combination of T, U, and V, this function will use Rtuv_expr to compile the respective expression and from then on use this method -- no recursion anymore:
#generated function Rtuv{T, U, V, X<:Real}(::Type{Val{T}}, ::Type{Val{U}}, ::Type{Val{V}},
n::Int, p::Real, RPC::Vector{X})
Rtuv_expr(T, U, V, :n, :p, :RPC)
end
You have to call it with t, u, v wrapped in Val, though:
julia> Rtuv(Val{1}, Val{2}, Val{1}, 0, 0.1, rand(3))
-0.0007782250832001092
If you test a small loop like this,
for t = 0:3, u = 0:3, v = 0:3
println(Rtuv(Val{t}, Val{u}, Val{v}, 0, 0.1, [1.0, 2.0, 3.0]))
end
it will need some time for the first run, but then go pretty fast, since the used methods are already compiled.

Resources