How to deal with the edge weight in the graph in minizinc? - solver

I have a task like the follow figure:
I need code a optimization model in Minizinc to solver placement problem, that is, solve give a placement strategy to indicate which Host should a, b, c to place.
One of the chanllenge that I faced is the constraint that the resource requirement do not exceed the resource.
I did it like:
int: numHosts = 5;
set of int: hosts = 1..numHosts;
int: numRel = 2;
set of int: relindx = 1..numRel;
array[relindx] of int: preNode = [1, 1]; % edge (1, 2), (2, 3) a=1, b=2, c=3
array[relindx] of int: postNode = [2, 3];
int: sliceLen = 3;
set of int: sSlice = 1..sliceLen;
array[sSlice] of int: slice = [1, 2, 3]; % a, b, c
int: numVnfs = 5; % types of rectangle(a, b, c, d, e)
set of int: vnfs = 1..numVnfs;
array[vnfs, vnfs] of int: bandwidth_resource = array2d(1..numHosts, 1..numHosts, [0,0,30,0,0, 0,0,35,0,30, 30,35,0,0,40, 0,0,0,0,35, 0,30,40,35,0]); % array2d save the edge resources
array[vnfs, vnfs] of int: vnf_bandwidth = array2d(1..numVnfs, 1..numVnfs, [0,2,2,4,4, 2,0,3,4,2, 2,3,0,4,3, 4,4,4,0,2, 4,2,3,2,0]); % array2d save the source requirement of rectangle
% DECISION VARIABLES
array[sSlice] of var hosts: placement;
array[vnfs, vnfs] of var int: bandwidth_used;
% CONSTRAINTS
constraint forall(host1 in hosts, host2 in hosts)
(
bandwidth_used[host1, host2] = sum(c1 in preNode, c2 in postNode where placement[c1] = host1 /\ placement[c2] = host2) (vnf_bandwidth[c1, c2])
);
constraint forall(vnf in vnfs)
(
bandwidth_used[vnf, vnf] <= bandwidth_resource[vnf, vnf]
);
Now, the First question is solver can give a plecement but bandwidth_used connot calculate coorectly.
the second question is how to sum the resource used that host do not conected directly
For example, in the figure rectangle a placed on Host1 and rectangle b placed on Host2, so the bandwidth_used should calculate the resource used in both edge (Host1, Host3) and edge (Host2, Host3).
Could you help me?

It seems that your problem is a mapping problem with communication constraints on bandwidth. Communication between two tasks mapped into two hosts can, in fact, be routed in different ways. You propose (Host1, Host3) and (Host3, Host2) but it can also be routed (Host1, Host3), (Host3, Host5) and (Host5, Host2). This can be modelled by network flow constraints (one constraint for each communication). For more details you can check our minizinc model in https://github.com/MiniZinc/minizinc-benchmarks/tree/master/mapping.
Hope it helps.

Related

Linear problem solving with matrix constraints in Rust

I am trying to rewrite a fairness ranking algorithm (source: https://arxiv.org/abs/1802.07281) from Python to Rust. The objective is finding a document-ranking probability matrix that is doubly stochastic and, by use of an utility vector (i.e. the document relevance in this case) gives fair exposure to all document types.
The objective is thus to maximise the expected utility under the following constraints:
sum of probabilities for each position equals 1;
sum of probabilities for each document equals 1;
every probibility is valid (i.e. 0 <= P[i,j] <= 1);
P is fair (disparate treatment constraints).
In Python we have done this using CVXPY:
u = documents[['rel']].iloc[:n].values.ravel() # utility vector
v = np.array([1.0 / (np.log(2 + i)) for i in range(n)]) # position discount vector
P = cp.Variable((n, n)) # linear maximizing problem uͭPv s.t. P is doubly stochastic and fair.
# Construct f in fͭPv such that for P every group's exposure divided by mean utility should be
# equal (i.e. enforcing DTC). Do this for the set of every individual two groups:
# example: calculated f for three groups {a, b, c}
# resulting constraints: [a - b == 0, a - c == 0, b - c == 0]
groups = {k: group.index.values for k, group in documents.iloc[:n].groupby('document_type')}
fairness_constraints = []
for k0, k1 in combinations(groups, 2):
g0, g1 = groups[k0], groups[k1]
f_i = np.zeros(n)
f_i[g0] = 1 / u[g0].sum()
f_i[g1] = -1 / u[g1].sum()
fairness_constraints.append(f_i)
# Create convex problem to solve for finding the probabilities that
# a document is at a certain position/rank, matching the fairness criteria
objective = cp.Maximize(cp.matmul(cp.matmul(u, P), v))
constraints = ([cp.matmul(np.ones((1, n)), P) == np.ones((1, n)), # ┤
cp.matmul(P, np.ones((n,))) == np.ones((n,)), # ┤
0.0 <= P, P <= 1] + # └┤ doubly stochastic matrix constraints
[cp.matmul(cp.matmul(c, P), v) == 0 for c in fairness_constraints]) # DTC
prob = cp.Problem(objective, constraints)
prob.solve(solver=cp.CBC)
This works great for multiple solvers, including SCS, ECOS and CBC.
Now trying to implement the algorithm above to Rust, I have resolved to crates like good_lp and lp_modeler. These should both be able to solve linear problems using CBC as also demonstrated in the Python example above. I am struggling however to find examples on how to define the needed constraints on my matrix variable P.
The code below is my work in progress for rewriting the Python code in Rust, using in this case the lp_modeler crate as an example. The code below compiles but panics when run. Furthermore I don't know how to add the disparate treatment constraints in a way Rust likes, as no package seems to be able to accept equality constraints on two vectors.
let n = cmp::min(u.len(), 25);
let u: Array<f32, Ix1> = array![...]; // utility vector filled with dummy data
// position discount vector
let v: Array<f32, Ix1> = (0..n)
.map(|i| 1.0 / ((2 + i) as f32).ln())
.collect();
let P: Array<f32, Ix2> = Array::ones((n, n));
// dummy data for document indices and their types
let groups = vec![
vec![23], // type A
vec![8, 10, 16, 19], // type B
vec![0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 15, 21, 24], // type C
vec![14, 17, 18, 20, 22] // type D
];
let mut fairness_contraints: Vec<Vec<f32>> = Vec::new();
for combo in groups.iter().combinations(2).unique() {
let mut f_i: Vec<f32> = vec![0f32; n];
{ // f_i[g0] = 1 / u[g0].sum()
let usum_g0: f32 = combo[0].iter()
.map(|&i| u[i])
.sum();
for &i in combo[0].iter() {
f_i[i] = 1f32 / usum_g0;
}
}
{ // f_i[g1] = -1 / u[g1].sum()
let usum_g1: f32 = combo[1].iter()
.map(|&i| u[i])
.sum();
for &i in combo[1].iter() {
f_i[i] = -1.0 / usum_g1;
}
}
fairness_contraints.push(f_i);
}
let mut problem = LpProblem::new("Fairness", LpObjective::Maximize);
problem += u.dot(&P).dot(&v); // Expected utility objective
// Doubly stochastic constraints
for col in P.columns() { // Sum of probabilities for each position
problem += sum(&col.to_vec(), |&el| el).equal(1);
}
for row in P.rows() { // Sum of probabilities for each document
problem += sum(&row.to_vec(), |&el| el).equal(1);
}
// Valid probability constraints
for el in P.iter() {
problem += lp_sum(&vec![el]).ge(0);
problem += lp_sum(&vec![el]).le(1);
}
// TODO: implement DTC fairness constraints
let solver = CbcSolver::new();
let result = solver.run(&problem);
Can anybody give me a nudge in the right direction on this specific problem? Thanks in advance!

How to solve a McNuggets problem using z3py

I am new to z3py and wondering if this problem can be easily solved using "from z3 import *".
The McNuggets version of the coin problem was introduced by Henri Picciotto,
who included it in his algebra textbook co-authored with Anita Wah. Picciotto
thought of the application in the 1980s while dining with his son at
McDonald's, working the problem out on a napkin. A McNugget number is
the total number of McDonald's Chicken McNuggets in any number of boxes.
In the United Kingdom, the original boxes (prior to the introduction of
the Happy Meal-sized nugget boxes) were of 6, 9, and 20 nuggets.
[Wikipedia]
Task
McDonald is selling McNuggets in these boxes A=6, B= 9, C=20, D=27. Your friends and you are hungry and want to eat X chicken pieces.
first question: is possible to buy S boxes of size A, T boxes of size B, U boxes of size C and V boxes of size D such that you get exactly X chicken pieces (without left over)? (for example x=36)
second question: determine the minimal number X which gives a satisfiable solution, while for Y=X-1 it is not satisfiable and thus this Y is the solution of the Chicken McNuggets problem for the fixed A, B, C, D values above. This means that it is the largest number Y which can NOT be represented this way, or in terms of chicken pieces, no matter how many (S,T,U,V) boxes of the given sizes (A,B,C,D) you buy and your friends do eat exactly Y pieces, then there has to be some left over pieces.
Stack-overflow works the best if you show what you tried, and what sort of problems you ran into. I'm guessing you're not quite familiar with the idioms with z3py: Start by reading through https://ericpony.github.io/z3py-tutorial/guide-examples.htm which will get you on the right track.
Having said that, the first question is trivial to code in z3py:
from z3 import *
A = 6
B = 9
C = 20
D = 27
S, T, U, V = Ints('S T U V')
X = 36
s = Solver()
s.add(S >= 0)
s.add(T >= 0)
s.add(U >= 0)
s.add(V >= 0)
s.add(S*A + T*B + U*C + V*D == X)
while s.check() == sat:
m = s.model()
print(m)
block = []
for var in [S, T, U, V]:
v = m.eval(var, model_completion=True)
block.append(var != v)
s.add(Or(block))
This prints:
[S = 6, T = 0, U = 0, V = 0]
[S = 0, T = 1, U = 0, V = 1]
[S = 3, T = 2, U = 0, V = 0]
[S = 0, T = 4, U = 0, V = 0]
giving you all the solutions.
The second question is a bit confusing to read, but you might want to use the Optimize object instead of Solver. Start by reading through https://rise4fun.com/Z3/tutorial/optimization and see if you can make progress. If not, feel free to ask a new question; detailing what problem you ran into. (The tutorial there is in SMTLib, but you can do the same in Python using the Optimize class.)

How to generate puzzles to 'crack the code'? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
In a puzzle book I found the following puzzle:
The caption is in Dutch, but I can shortly describe it:
There is a sequence of numbers in the range 0...6, which is not given
There are 6 mathematical statements (listed below) that are true
By using logic and crossing off certain numbers that you know are certainly not it, whomever plays the puzzle can find the sequence of numbers (the code).
For example, in the pictured case, we know that A+C=5, thus we can infer that both A and C can not be 6. By doing these repeatedly, you will find the sequence.
Now, my question is: How could I write an algorithm that generates these puzzle values?
I've tried to come up with a random sequence, and describe it with 6 similar mathematical statements, but in some cases the puzzle will be unsolvable.
Such an unsolvable case / statements are for example when the sequence is 012345, with statements A+B=1 B+C=3 C+D=5 D+E=7 E+F=9 F+A=5
First, let's elaborate a solution S for this problem:
For each variable, create a set {0,1,2,3,4,5,6} with its possible values.
Analyse each equation and cut values from the variables' sets based on the equations.
example: A + B = 3 (we can cut 4, 5 and 6 from A and B sets).
When all sets have only 1 element, that's your answer.
On the other hand, if all equations are analysed and no set changes, it's impossible.
Example: (1) A + C = 5 (2) B - D = 5 (3) B + C = 6
(4) E * F = 6 (5) B - E = 3 (6) A + D = 6
Analysing (1): Reduce A and C to {0,1,2,3,4,5}.
Analysing (2): Reduce B to {5,6}. Reduce D to {0,1}.
Analysing (3): Reduce C to {0,1}
Analysing (4): Reduce E and F to {1,2,3,6}.
Analysing (5): Can't reduce.
Analysing (6): Reduce A to {5}. Reduce D to {1}.
--------------------------------------------------
Not over yet, but something changed. Restart:
--------------------------------------------------
Analysing (1): Reduce C to {0}
Analysing (2): Reduce B to {6}.
Analysing (3): Can't reduce.
Analysing (4): Reduce E and F to {1,2,3,6}.
Analysing (5): Reduce E to {3}.
Analysing (6): Can't reduce.
--------------------------------------------------
Not over yet, but something changed. Restart:
--------------------------------------------------
Analysing (1): Can't reduce.
Analysing (2): Can't reduce.
Analysing (3): Can't reduce.
Analysing (4): Reduce F to {2}.
Analysing (5): Can't reduce.
Analysing (6): Can't reduce.
--------------------------------------------------
Over. All sets of size 1. Answer: (5,6,0,1,3,2)
--------------------------------------------------
Now, knowing how to solve, I would create puzzles the following way:
Choose a random answer.
example: (4, 1, 3, 2, 0, 5).
Generate 6 random equations with it.
Run S with this equations.
If S ends, you have a possible group of equations.
Otherwise, restart.
There are 7^6 = 117649 possible codes. With 6 questions, we only need each to remove 6/7 of the search space. If the first few do more, then so much the better.
For the three questions, it is easy. When you look at the distribution of ways to get a sum or a difference you find that there are can be no more than 7/49 = 49 ways to get an answer and usually less. So partition A, B, C, D, E, F into 3 pairs of 2, supply random operations, and you have no more than 343 possible answers left.
With your example, I randomly generated D-A=4, C+F=7, D-B=2. For the first pair we have 3 possibilities, for the second we have 6, for the third we have 5.
Now what we need to do is actually construct all of the possibilities (in this case there are 90 of them). And then you can construct random statements, and only accept ones that are on the path to 1 solution. Which means that with 3 questions left, you cut down by a factor of at least the cube-root (in this case leaving no more than 20 possibilities), with 2 by the square root (leaving no more than 4), and then a single possibility.
Given that a random question on average cuts your search space by at least 6/7, random questions are likely to do this pretty easily. (The challenge is in verifying the answer.)
This seems like nothing more than simple algebraic substitutions. Moreover, the choice of operations in the equations does not matter. From
(D, B) (B, C)
we get
(D, C)
then from
(D, C) (C, A)
we get
(D, A)
An equation for (A, D) already exists so we can solve for both. From there, it's easy to see how to complete the solution.
In order to create a puzzle, start with any such double equation, say
(E, F) (E, F)
then split one of them into the more obscure, like
(E, B) (B, F)
that gives us three of the six equations (remember the choice of operations can be purely random). I leave the reader to give more thought to completion.
I wouldn't expect completion and implementation to be trivial but hopefully this can give us an idea of how this can be done quite deliberately without backtracking.
JavaScript code:
const vars = ["A", "B", "C", "D", "E", "F"];
function getOps(pair){
return pair.includes(0) ? ["+", "-"] : ["+", "-", "*"];
}
function getRandom(k, list){
let result = [];
for (let i=0; i<k; i++)
result = result.concat(
list.splice(~~(Math.random()*list.length), 1));
return result;
}
function getNum(a, b, op){
return eval(`${ a } ${ op } ${ b }`);
}
function getEquation(a, b, op, idxs){
// Randomise the order of the variables
if (Math.random() > 0.5)
[a, b] = [b, a];
return `${ vars[idxs[a]] } ${ op } ${ vars[idxs[b]] } = ${ getNum(a, b, op) }`;
}
function f(){
let remaining = [0, 1, 2, 3, 4, 5, 6];
let result = [];
// Remove one entry
remaining.splice(~~(Math.random()*7), 1);
// Shuffle
remaining = getRandom(6, remaining);
const idxs = Object.fromEntries(
remaining.map((x, i) => [x, i]));
// Select equation pairs
const [a, b] = getRandom(2, remaining);
const [c, d] = getRandom(2, remaining);
result.push(
getEquation(a, c, getRandom(1, getOps([a, c])), idxs),
getEquation(a, d, getRandom(1, getOps([a, d])), idxs),
getEquation(b, c, getRandom(1, getOps([b, c])), idxs),
getEquation(b, d, getRandom(1, getOps([b, d])), idxs)
);
const [e] = getRandom(1, remaining);
const [f] = remaining;
const [aa] = getRandom(1, [a, b, c, d]);
result.push(
getEquation(e, f, getRandom(1, getOps([e, f])), idxs),
getEquation(e, aa, getRandom(1, getOps([e, aa])), idxs)
);
const legend = Object.entries(idxs)
.map(([x, i]) => [vars[i], Number(x)])
.map(([a, b]) => `(${ a } ${ b })`)
.sort()
.join(' ');
return {
equations: getRandom(6, result).join('\n'),
legend: legend
};
}
var result = f();
console.log(result.equations);
console.log('');
console.log(result.legend);

Solving systems of second order differential equations

I'm working on a script in mathematica that will take simulate a string held at either end and plucked, by solving the wave equation via numerical methods. (http://en.wikipedia.org/wiki/Wave_equation#Investigation_by_numerical_methods)
n = 5; (*The number of discreet elements to be used*)
L = 1.0; (*The length of the string that is vibrating*)
a = 1.0/3.0; (*The distance from the left side that the string is \
plucked at*)
T = 1; (*The tension in the string*)
[Rho] = 1; (*The length density of the string*)
y0 = 0.1; (*The vertical distance of the string pluck*)
[CapitalDelta]x = L/n; (*The length of each discreet element*)
m = ([Rho]*L)/n;(*The mass of each individual node*)
c = Sqrt[T/[Rho]];(*The speed at which waves in the string propogate*)
I set all my variables
Y[t] = Array[f[t], {n - 1, 1}];
MatrixForm(*Creates a vector size n-1 by 1 of functions \
representing each node*)
I define my Vector of nodal position functions
K = MatrixForm[
SparseArray[{Band[{1, 1}] -> -2, Band[{2, 1}] -> 1,
Band[{1, 2}] -> 1}, {n - 1,
n - 1}]](*Creates a matrix size n by n governing the coupling \
between each node*)
I create the stiffness matrix relating all the nodal functions to one another
Y0 = MatrixForm[
Table[Piecewise[{{(((i*L)/n)*y0)/a,
0 < ((i*L)/n) < a}, {(-((i*L)/n)*y0)/(L - a) + (y0*L)/(L - a),
a < ((i*L)/n) < L}}], {i, 1, n - 1}]]
I define the initial positions of each node using a piecewise function
NDSolve[{Y''[t] == (c/[CapitalDelta]x)^2 Y[t].K, Y[0] == Y0,
Y'[0] == 0},
Y, {t, 0, 10}];(*Numerically solves the system of second order DE's*)
Finally, This should solve for the values of the individual nodes, but it returns an error:
"NDSolve::ndinnt : Initial condition [Y0 table] is not a number or a rectangular array"
So , it would seem that I don't have a firm grasp on how matrices work in mathematica. I would greatly appreciate it if anyone could help me get this last line of code to run properly.
Thank you,
Brad
I don't think you should use MatrixForm when defining the matrices. MatrixForm is used to format a list of list as a matrix, usually when you display it. Try removing it and see if it works.

How to find optimal overlap of noisy bivalent matricies

I'm dealing with an image processing problem that I've simplified as follows. I have three 10x10 matrices, each with the values 1 or -1 in each cell. Each matrix has an irregular object located somewhere, and there is some noise in the matrix. I'd like to figure out how to find the optimal alignment of the matrices that would let me line up the objects so I can get their average.
With the 1/-1 coding, I know that the product of two matrices (using element-wise multiplication, not matrix multiplication) will yield 1 if there is a match between two multiplied cells and -1 if there is a mismatch, thus the sum of the products yields a measure of overlap. With this, I know I can try out all possible alignments of two matrices to find that which yields the optimal overlap, but I'm not sure how to do this with 3 matrices (or more - I really have 20+ in my actual data set).
To help clarify the problem, here is some code, written in R, that sets up the sort of matricies I'm dealing with:
#set up the 3 matricies
m1 = c(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1)
m1 = matrix(m1,10)
m2 = c(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1)
m2 = matrix(m2,10)
m3 = c(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1)
m3 = matrix(m3,10)
#show the matricies
image(m1)
image(m2)
image(m3)
#notice there's a "+" shaped object in each
#create noise
set.seed(1)
n1 = sample(c(1,-1),100,replace=T,prob=c(.95,.05))
n1 = matrix(n1,10)
n2 = sample(c(1,-1),100,replace=T,prob=c(.95,.05))
n2 = matrix(n2,10)
n3 = sample(c(1,-1),100,replace=T,prob=c(.95,.05))
n3 = matrix(n3,10)
#add noise to the matricies
mn1 = m1*n1
mn2 = m2*n2
mn3 = m3*n3
#show the noisy matricies
image(mn1)
image(mn2)
image(mn3)
Here is a program in Mathematica that does what you want (I think).
I may explain it in more detail, if you need.
(*define temp tables*)
r = m = Table[{}, {100}];
(*define noise function*)
noise := Partition[RandomVariate[BinomialDistribution[1, .05], 100],
10];
For[i = 1, i <= 100, i++,
(*generate 100 10x10 matrices with the random cross and noise added*)
w = RandomInteger[6]; h = w = RandomInteger[6];
m[[i]] = (ArrayPad[CrossMatrix[4, 4], {{w, 6 - w}, {h, 6 - h}}] +
noise) /. 2 -> 1;
(*Select connected components in each matrix and keep only the biggest*)
id = Last#
Commonest[
Flatten#(mf =
MorphologicalComponents[m[[i]], CornerNeighbors -> False]), 2];
d = mf /. {id -> x, x_Integer -> 0} /. {x -> 1};
{minX, maxX, minY, maxY} =
{Min#Thread[g[#]] /. g -> First,
Max#Thread[g[#]] /. g -> First,
Min#Thread[g[#]] /. g -> Last,
Max#Thread[g[#]] /. g -> Last} &#Position[d, 1];
(*Trim the image of the biggest component *)
r[[i]] = d[[minX ;; maxX, minY ;; maxY]];
]
(*As the noise is low, the more repeated component is the image*)
MatrixPlot ## Commonest#r
Result:

Resources