How to get consistent ortools assignment results? - or-tools

The problem is to assign items into a few regions. Each item pairs have a crossing number, and the objective is to minimize the crossing of items across the regions. Each item also has a size and there is a limitation for the size of each region.
I am able to solve the problem with the following code, but I am getting different results every time. I would like to consistently get the same results.
I have tried to set "solver.parameters.random_seed = 1" but it does not work.
import numpy as np
from ortools.sat.python import cp_model
import random
num_items = 15
num_regions = 3
max_size = 600
random.seed(1)
matrix = [[random.randint(0,99) for _ in range(num_items)] for _ in range(num_items)]
size_array = [random.randint(0,99) for _ in range(num_items)]
# Model
model = cp_model.CpModel()
# Variables
# x[a, b] is a matrix of 0-1 variables, which will be 1
# if item a is assigned to region b.
x = []
for a in range(num_items):
t = []
for b in range(num_regions):
t.append(model.NewBoolVar(f'x[{a},{b}]'))
x.append(t)
# y[a_i, a_j, b_i, b_j] is a matrix of 0-1 variables, which will be 1
# if x[a_i, b_i] = 1 AND x[a_j, b_j] = 1
y = []
for a_i in range(num_items):
t1 = []
for a_j in range(num_items):
t2 = []
for b_i in range(num_regions):
t3 = []
for b_j in range(num_regions):
p = model.NewBoolVar(f'y[{a_i},{a_j},{b_i},{b_j}]')
t3.append(p)
x1 = x[a_i][b_i]
x2 = x[a_j][b_j]
model.AddBoolOr([x1.Not(), x2.Not(), p])
model.AddImplication(p, x1)
model.AddImplication(p, x2)
t2.append(t3)
t1.append(t2)
y.append(t1)
# Constraints
# Each item is assigned to 1 region.
for a in range(num_items):
model.Add(sum([x[a][b] for b in range(num_regions)]) == 1)
# Each region total item's size less than max_size.
for b in range(num_regions):
model.Add(sum([x[a][b]*int(np.ceil(size_array[a])) for a in range(num_items)]) <= max_size)
def crossing(b_i, b_j):
objective_terms = []
for a_i in range(num_items):
for a_j in range(num_items):
objective_terms.append(y[a_i][a_j][b_i][b_j] * int(np.ceil((matrix[a_i][a_j]+matrix[a_j][a_i]))))
return objective_terms
# Objective
# Each item pairs has a crossing value
# Minimize the crossing across regions
objective_terms = []
objective_terms.extend(crossing(0, 1))
objective_terms.extend(crossing(1, 2))
objective_terms.extend(2*crossing(0, 2))
model.Minimize(sum(objective_terms))
# Solve
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8
solver.parameters.random_seed = 1
status = solver.Solve(model)
print("Status = {}".format(solver.StatusName(status)), flush=True)
# Print solution
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f'Total cost = {solver.ObjectiveValue()}', flush=True)
for b in range(num_regions):
print("Region {} :".format(b), end='', flush=True)
total_size = 0
for a in range(num_items):
# Test if x[a, b] is 1 (with tolerance for floating point arithmetic).
if solver.BooleanValue(x[a][b]):
total_size += size_array[a]
print(" Total size of items are {} ".format(str(total_size)), flush=True)
Result 1:
Status = OPTIMAL
Total cost = 1274.0
Region 0 : Total size of items are 581
Region 1 : Total size of items are 90
Region 2 : Total size of items are 0
Result 2:
Status = OPTIMAL
Total cost = 1274.0
Region 0 : Total size of items are 0
Region 1 : Total size of items are 90
Region 2 : Total size of items are 581

Setting num_search_workers = 1 works, thanks!

Related

Referencing value of an array based on the values of another

I have an array d = [0,1000,2000]. Based on this array, I compute the value of another array, let's say J = [0,5000,8000], where J = 3*d+2000.
Now, during iteration using a for loop, if d=0, I want to extract value of J(1); if d = 1000, then I want to extract values of J(1) and J(2); if d = 2000, I want to extract values of J(1),J(2) and J(3). What would be a generic way to cross-reference values of two arrays?
Assuming your values in d are unique and the length of d and J are identical, use MATLAB's find function, especially using this version with n = 1, and direction = 'first', like so:
idx = find(d == ii, 1, 'first')
Here, ii is the desired value, e.g. 0, 1000, and so on. You'll get the index of the (first) occurrence of the desired value in d. Then, just extract all values from J from 1 to idx:
J(1:idx)
Here's a small test script:
d = [0, 1000, 2000]
J = 3 * d + 2000
% If your counter variable only contains valid values from d
for ii = d
idx = find(d == ii, 1, 'first');
printf('d = %d\n', ii);
printf('Extracted values are: ');
printf('%d ', J(1:idx));
printf('\n \n');
end
% If your counter variable may contain any value
for ii = 0:2000
idx = find(d == ii, 1, 'first');
if (~isempty(idx))
printf('d = %d\n', ii);
printf('Extracted values are: ');
printf('%d ', J(1:idx));
printf('\n \n');
end
end
And, the output looks like this:
d =
0 1000 2000
J =
2000 5000 8000
d = 0
Extracted values are: 2000
d = 1000
Extracted values are: 2000 5000
d = 2000
Extracted values are: 2000 5000 8000
d = 0
Extracted values are: 2000
d = 1000
Extracted values are: 2000 5000
d = 2000
Extracted values are: 2000 5000 8000
Hope that helps!
P.S. I haven't thought about vectorization here, since the question states, that a for loop is used in any case.

Vectorization in Matlab to speed up expensive loop

How can I speed up the following MATLAB code, using vectorization? Right now the single line in the loop is taking hours to run for the case upper = 1e7.
Here is the commented code with sample output:
p = 8;
lower = 1;
upper = 1e1;
n = setdiff(lower:upper,primes(upper)); % contains composite numbers between lower + upper
x = ones(length(n),p); % Preallocated 2-D array of ones
% This loop stores the unique prime factors of each composite
% number from 1 to n, in each row of x. Since the rows will have
% varying lengths, the rows are padded with ones at the end.
for i = 1:length(n)
x(i,:) = [unique(factor(n(i))) ones(1,p-length(unique(factor(n(i)))))];
end
output:
x =
1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1
2 3 1 1 1 1 1 1
2 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
2 5 1 1 1 1 1 1
For example, the last row contains the prime factors of 10, if we ignore the ones. I have made the matrix 8 columns wide to account for the many prime factors of numbers up to 10 million.
Thanks for any help!
This is not vectorization, but this version of the loop will save about half of the time:
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
Here is a quick benchmark for this:
function t = getPrimeTime
lower = 1;
upper = 2.^(1:8);
t = zeros(numel(upper),2);
for k = 1:numel(upper)
n = setdiff(lower:upper(k),primes(upper(k))); % contains composite numbers between lower to upper
t(k,1) = timeit(#() getPrime1(n));
t(k,2) = timeit(#() getPrime2(n));
disp(k)
end
p = plot(log2(upper),log10(t));
p(1).Marker = 'o';
p(2).Marker = '*';
xlabel('log_2(range of numbers)')
ylabel('log(time (sec))')
legend({'getPrime1','getPrime2'})
end
function x = getPrime1(n) % the originel function
p = 8;
x = ones(length(n),p); % Preallocated 2-D array of ones
for k = 1:length(n)
x(k,:) = [unique(factor(n(k))) ones(1,p-length(unique(factor(n(k)))))];
end
end
function x = getPrime2(n)
p = 8;
x = ones(numel(n),p); % Preallocated 2-D array of ones
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
end
Here's another approach:
p = 8;
lower = 1;
upper = 1e1;
p = 8;
q = primes(upper);
n = setdiff(lower:upper, q);
x = bsxfun(#times, q, ~bsxfun(#mod, n(:), q));
x(~x) = inf;
x = sort(x,2);
x(isinf(x)) = 1;
x = [x ones(size(x,1), p-size(x,2))];
This seems to be faster than the other two options (but is uses more memory). Borrowing EBH's benchmarking code:
function t = getPrimeTime
lower = 1;
upper = 2.^(1:12);
t = zeros(numel(upper),3);
for k = 1:numel(upper)
n = setdiff(lower:upper(k),primes(upper(k)));
t(k,1) = timeit(#() getPrime1(n));
t(k,2) = timeit(#() getPrime2(n));
t(k,3) = timeit(#() getPrime3(n));
disp(k)
end
p = plot(log2(upper),log10(t));
p(1).Marker = 'o';
p(2).Marker = '*';
p(3).Marker = '^';
xlabel('log_2(range of numbers)')
ylabel('log(time (sec))')
legend({'getPrime1','getPrime2','getPrime3'})
grid on
end
function x = getPrime1(n) % the originel function
p = 8;
x = ones(length(n),p); % Preallocated 2-D array of ones
for k = 1:length(n)
x(k,:) = [unique(factor(n(k))) ones(1,p-length(unique(factor(n(k)))))];
end
end
function x = getPrime2(n)
p = 8;
x = ones(numel(n),p); % Preallocated 2-D array of ones
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
end
function x = getPrime3(n) % Approach in this answer
p = 8;
q = primes(max(n));
x = bsxfun(#times, q, ~bsxfun(#mod, n(:), q));
x(~x) = inf;
x = sort(x,2);
x(isinf(x)) = 1;
x = [x ones(size(x,1), p-size(x,2))];
end

filling sparse matrices efficiently matlab

I am working with a sparse matrix of very large size:
U = sparse(a,b) % a and b are very large
On the hand, there exists the cell Ind which has 'a' rows. In each row, there exists a 'variate' number of elements, e.g. :
Ind{1} = [1 3 5 19 1000 1340]
Ind{2} = [9 100 1500 1600 8000 b]
...
Ind{a} = [3 5 6 90 1000 4300 5712 9480]
as could be seen the maximum index number in Ind{i} can be 'b'. For each of these index vector also exists a content matrix like 'c' :
c = [2 3 1 6 3 5 1 3 4 1 2 ... 5]
Here is the question, for each element in Ind{i}, I want to fill the 'row = i' and the 'col=Ind{i}' with c(Ind{i}), i.e.
for i = 1 : a
U(i,Ind{i}) = c(Ind{i}) ;
end
the problem is 'a' is very large and the loop takes long time to be computed. Any idea to avoid looping?
I'm not sure if there is a way to avoid the loop, but I do get a factor of 2-to-20 speed increase (I ranged a from 3 to 5,000 with b fixed at 10,000) by building three large vectors (two for row and column indices and one for values) and building the sparse matrix after the loop:
strides = cellfun(#numel,Ind);
n = sum(strides);
I(n,1) = 0;
J(n,1) = 0;
S(n,1) = 0;
bot = 1;
for k = 1:a
top = bot + strides(k) - 1 ;
mask = bot:top ;
%
I(mask) = k ;
J(mask) = Ind{k} ;
S(mask) = c(Ind{k}) ;
%
bot = top + 1;
end
U = sparse(I,J,S,a,b);
This is the recommend usage of sparse because assignments to a sparse matrix are more costly than regular arrays.

How to create vector of binary values based on correspondence between two other vectors in MATLAB [duplicate]

I'm developing a program with MatLab that calculates powers of numbers, adds them together, and then sees if any of the first set of numbers (numbers to powers) equals any of the added numbers to powers. I'm trying to check this for each value in the first array, however, I am getting an output like this:
m =
1
128
2187
16384
78125
279936
823543
2097152
4782969
10000000
for each m value, which is just the result of a simple for loop of the array. So when I go to check if m is in the array, it checks is [1, 128,2187,16384,78125...] in the array, and the answer is no. How can I get it to evaluate each individual entry, like this:
Array n is [1,128,2187,16384]
for m = n
m = 1
Is m in array? No
m = 128
Is m in array? No
m = 2187
Is m in array? Yes
m = 16384
Is m in array? No
end
My code is below:
C = [];
D = [];
E = [];
F = [];
numbers1 = [];
numbers2 = [];
numbers = 10;
powers = 10;
for i = 1:numbers
for j = 3:powers
C = [C;i^j];
end
C = transpose(C);
D = [D;C];
C = [];
end
[~,b] = unique(D(:,1)); % indices to unique values in first column of D
D(b,:); % values at these rows
for i = D
for a = D
E = [E;i+a];
end
E = transpose(E);
F = [F;E];
E = [];
end
[~,b] = unique(F(:,1)); % indices to unique values in first column of F
F(b,:); % values at these rows
for m = D % this is the for loop mentioned above
m
end
Example vectors:
>> m = [1 3 5 9];
n = [5 2 1 4 8];
To check if each element of vector m is in n, use ismember:
>>ismember(m,n)
ans =
1 0 1 0
To get the values, not the indices: use logical indexing on m:
>> m(ismember(m,n))
ans =
1 5
or directly use intersect:
>> intersect(m,n)
ans =
1 5

Single layer neural network [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
For the implementation of single layer neural network, I have two data files.
In:
0.832 64.643
0.818 78.843
Out:
0 0 1
0 0 1
The above is the format of 2 data files.
The target output is "1" for a particular class that the corresponding input belongs to and "0" for the remaining 2 outputs.
The problem is as follows:
Your single layer neural network will
find A (3 by 2 matrix) and b (3 by 1
vector) in Y = A*X + b where Y is [C1,
C2, C3]' and X is [x1, x2]'.
To solve the problem above with a
neural network, we can re-write the
equation as follow: Y = A' * X' where
A' = [A b] (3 by 3 matrix) and X' is
[x1, x2, 1]'
Now you can use a neural network with
three input nodes (one for x1, x2, and
1 respectively) and three outputs (C1,
C2, C3).
The resulting 9 (since we have 9
connections between 3 inputs and 3
outputs) weights will be equivalent to
elements of A' matrix.
Basicaly, I am trying to do something like this, but it is not working:
function neuralNetwork
load X_Q2.data
load T_Q2.data
x = X_Q2(:,1);
y = X_Q2(:,2);
learningrate = 0.2;
max_iteration = 50;
% initialize parameters
count = length(x);
weights = rand(1,3); % creates a 1-by-3 array with random weights
globalerror = 0;
iter = 0;
while globalerror ~= 0 && iter <= max_iteration
iter = iter + 1;
globalerror = 0;
for p = 1:count
output = calculateOutput(weights,x(p),y(p));
localerror = T_Q2(p) - output
weights(1)= weights(1) + learningrate *localerror*x(p);
weights(2)= weights(1) + learningrate *localerror*y(p);
weights(3)= weights(1) + learningrate *localerror;
globalerror = globalerror + (localerror*localerror);
end
end
I write this function in some other file and calling it in my previous code.
function result = calculateOutput (weights, x, y)
s = x * weights(1) + y * weights(2) + weights(3);
if s >= 0
result = 1;
else
result = -1;
end
I can spot a few problems with the code. The main issue is that the target is multi-class (not binary), so you need to either use 3 output nodes one for each class (called 1-of-N encoding), or use a single output node with a different activation function (something capable of more than just binary output -1/1 or 0/1)
In the solution below, the perceptron has the following structure:
%# load your data
input = [
0.832 64.643
0.818 78.843
1.776 45.049
0.597 88.302
1.412 63.458
];
target = [
0 0 1
0 0 1
0 1 0
0 0 1
0 0 1
];
%# parameters of the learning algorithm
LEARNING_RATE = 0.1;
MAX_ITERATIONS = 100;
MIN_ERROR = 1e-4;
[numInst numDims] = size(input);
numClasses = size(target,2);
%# three output nodes connected to two-dimensional input nodes + biases
weights = randn(numClasses, numDims+1);
isDone = false; %# termination flag
iter = 0; %# iterations counter
while ~isDone
iter = iter + 1;
%# for each instance
err = zeros(numInst,numClasses);
for i=1:numInst
%# compute output: Y = W*X + b, then apply threshold activation
output = ( weights * [input(i,:)';1] >= 0 ); %#'
%# error: err = T - Y
err(i,:) = target(i,:)' - output; %#'
%# update weights (delta rule): delta(W) = alpha*(T-Y)*X
weights = weights + LEARNING_RATE * err(i,:)' * [input(i,:) 1]; %#'
end
%# Root mean squared error
rmse = sqrt(sum(err.^2,1)/numInst);
fprintf(['Iteration %d: ' repmat('%f ',1,numClasses) '\n'], iter, rmse);
%# termination criteria
if ( iter >= MAX_ITERATIONS || all(rmse < MIN_ERROR) )
isDone = true;
end
end
%# plot points and one-against-all decision boundaries
[~,group] = max(target,[],2); %# actual class of instances
gscatter(input(:,1), input(:,2), group), hold on
xLimits = get(gca,'xlim'); yLimits = get(gca,'ylim');
for i=1:numClasses
ezplot(sprintf('%f*x + %f*y + %f', weights(i,:)), xLimits, yLimits)
end
title('Perceptron decision boundaries')
hold off
The results of training over the five sample you provided:
Iteration 1: 0.447214 0.632456 0.632456
Iteration 2: 0.000000 0.447214 0.447214
...
Iteration 49: 0.000000 0.447214 0.447214
Iteration 50: 0.000000 0.632456 0.000000
Iteration 51: 0.000000 0.447214 0.000000
Iteration 52: 0.000000 0.000000 0.000000
Note that the data used in the example above only contains 5 samples. You would get more meaningful results if you had more training instances in each class.