Minizinc: optimal ordering on table feature - minizinc

I have a table with features = {A,B}. B is a column of integers. Scanning the table, when I have a value change in B column, I increment a variable "changes" of 1:
if data[i,B]!=data[i-1,B]
then changes=changes+1
I want to find an order that minimizes changes and at the same time keep the repetition of a value in B in [0,upper_bound].
I'm thinking to use an array as a decision variable where save the position j for the element i:
order[i]=j means i element in data is the j-th element in ordering.
How can I model with constraint? This is what I do until now:
array[1..n, Features] of int: data;
int: changes=0;
constraint
forall(i in 1..n) (
if data[i,B] != data[i-1,B] then
changes=changes+1
endif
)
;
minimize changes;
I think I'm wrong using changes as a constant variable, right? Thank you in advance.

In MiniZinc (and in constraint programming in general) you cannot increment a variable as changes=changes+1).
If changes is a variable used only for the total count of changes you can use sum instead, something like:
% ...
var 0..n: num_changes;
constraint
changes = sum([data[i,B] != data[i-1,B] | i in 2..n])
;
% ...
However, if you want to use the number of accumulated changes for each i then you have to create a changes array to collect the values for each step, e.g.
var[1..n-1] of var 0..n: changes;
% the total number of changes (to minimize)
var 0..n-1: total_changes = changes[n-1];
constraint
forall(i in 1..n-1) (
if data[i,B] != data[i-1,B] then
changes[i] = changes[i-1]+1
else
changes[i] = changes[i-1]
endif
)
;

Related

infinite value while using cumulative constraint

I am stuck with a cumulative constraint I seem not to use properly, I seek for help ! :)
I have tasks with precedence and, for some of them, required & forbidden resources.
I need to decide when to start a task & who to assign to it.
To do so, I'm using an array of decision variable resource_allocation:
array[Tasks, Resources] of var 0..1: resource_allocation; %Selection of resources per task.
To manage the required/forbidden resources, I used the following:
% Mandatory & Forbidden constraint allocation
constraint forall(t in Tasks, r in resource_required[t])(resource_allocation[t,r]=1);
constraint forall(t in Tasks, r in resource_forbidden[t])(resource_allocation[t,r]=0);
resource_required being set of int storing the resources number that are required/forbidden.
Each resource represents 1 worker, and each worker can only perform one task at a time, so I am trying to state that, for every resources, the cumsum of allocation can at max be 1.
It might be important to note that start is also a decision variable.
% Constraint allocated to only one task at a time
constraint forall(t in Resources)(
cumulative(start, duration, [resource_allocation[t, r] | t in Tasks], 1)
);
Doing so, I always end up with the following error
JC:70.12-82
in call 'cumulative'
cumulative:21-3.49-7
in binary '/\' operator expression
cumulative:25-3.49-7
in if-then-else expression
cumulative:26-5.48-9
in binary '/\' operator expression
cumulative:30-5.48-9
in if-then-else expression
cumulative:47.7-32
in call 'fzn_cumulative'
fzn_cumulative:4-9.20-17
in let expression
fzn_cumulative:8-13.20-17
in if-then-else expression
fzn_cumulative:10-17.19-17
in let expression
fzn_cumulative:12.21-74
in variable declaration for 'late'
in call 'max'
with i = <expression>
MiniZinc: evaluation error: arithmetic operation on infinite value
Process finished with non-zero exit code 1.
I need a little guidance, I looked in the source code of fzn_cumulative, but I don't get what is going on.
Thanks !
You might consider to limit the domains of your decisions variables.
int is unlimited (disregarding the limited number of bits per int) and may lead to overflow situations or complaints about infinite values.
include "globals.mzn";
set of int: Tasks = 1..3;
set of int: Resources = 1..3;
set of int: Durations = 1..10;
set of int: Times = 1..1000;
% Use this editor as a MiniZinc scratch book
array[Tasks, Resources] of var 0..1: resource_allocation; %Selection of resources per task.
array [Tasks] of var Times: start;
array [Tasks] of var Durations: duration;
array [Tasks] of set of Resources: resource_required = [{1,2},{2,3},{3}];
array [Tasks] of set of Resources: resource_forbidden = [{},{1},{1}];
% Mandatory & Forbidden constraint allocation
constraint forall(t in Tasks, r in resource_required[t])(resource_allocation[t,r]=1);
constraint forall(t in Tasks, r in resource_forbidden[t])(resource_allocation[t,r]=0);
% Constraint allocated to only one task at a time
% Changed "t in Resources" to "r in Resources"
constraint forall(r in Resources)(
cumulative(start, duration, [resource_allocation[t, r] | t in Tasks], 1)
);

Why my array is of type var int instead of var set of int?

I have the following problem: I want to call the global constraint at_most but I got an error related to the signature
constraint forall(i in 0..w-1)(at_most(l_max, [board[i,j] | j in 0..l_max-1], 0..n));
the second argument does not match because it turns out to be var int instead of var set of int but I have previously defined board in this way:
set of int: VALUES = 0..n;
array[0..w-1,0..l_max-1] of var VALUES: board;
Just as a general message: at_most is among the list of deprecated constraints: https://www.minizinc.org/doc-2.5.5/en/lib-globals.html#deprecated-constraints.
Instead, you should use a count constraint. These constraints are more flexible and better supported by the solvers.
In this case there seems to be a misconception about what at_most does. At most only restrict the number of time a single value occurs. You are. however, giving it a full set of values.
If you are counting all the different values, then you instead can use global_cardinality_low_up. (You might also want to look at the closed version).
I think you meant to write the following constraint.
constraint forall(i in 0..w-1)(
global_cardinality_low_up([board[i,j] | j in 0..l_max-1], 0..n, [0 | i in 0..n], [l_max | i in 0..n])
);
This constraint insure that for the comprehensions the values in 0..n only occur l_max times.
Note that if you are using the comprehension to select a full row, then it would be better to use slice notation: board[i,..].

Printing part of an array in MiniZinc

I have a MiniZinc model for wolf-goat-cabbage in which I store the locations of each entity in its own array, e.g., array[1..max] of Loc: wolf where Loc is defined as an enum: enum Loc = {left, rght}; and max is the maximum possible number of steps needed, e.g., 20..
To find a shortest plan I define a variable var 1..max: len; and constrain the end state to occur at step len.
constraint farmer[len] == left /\ wolf[len] == left /\ goat[len] == left /\ cabbage[len] == left
Then I ask for
solve minimize len
I get all the right answers.
I'd like to display the arrays from 1..len, but I can't find a way to do it. When I try, for example, to include in the output:
[ "\(wolf[n]), " | n in 1..max where n <= len ]
I get an error message saying that I can't display an array of opt string.
Is there a way to display only an initial portion of an array, where the length of the initial portion is determined by the model?
Thanks.
Did you try to fix the len variable in the output statement like n <= fix(len)?. See also What is the use of minizinc fix function?

How to filter and save each variable on matlab

I have a data (matrix) with 3 columns : DATA=[ID , DATE, Value]
I want to filter my data by ID for example DATAid1= DATA where ID==1 and so on ..
for that I write this code in MATLAB
load calibrage_capteur.mat
data = [ID ,DATE , Valeur]
minid = min(data(:,1));
maxid = max(data(:,1));
for i=minid:maxid
ind=find(data(:,1) == i)
dataID = [ID(ind) ,DATE(ind) , Valeur(ind)]
end
As a result he register the last value in this example the max ID=31 so he register dataId31. Now I need how to save the variable each iteration. How can I do this?
You will want to use a cell array to hold your data rather than saving them as independent variables that are named based upon the ID.
data_by_ID = cell();
ids = minid:maxid;
for k = 1:numel(ids)
data_by_ID{k} = data(data(:,1) == ids(k),:);
end
Really though, depending on what you're doing with it, you can use data all of the time since all operations are going to be faster on a numeric matrix than they are on a cell array.
%// Do stuff with data ID = 10
do_stuff(data(data(:,1) == 10, :));
Update
If you absolutely must name your variables you could do the following (but please don't do this and use one of the methods above).
for k = 1:numel(ids)
eval(['dataId', num2str(ids(k)), '= data(k,:);']);
end
Your question is a bit unclear but it sounds like you simply want to save the result at each iteration of the for loop.
I'm assuming min and max id are arbitrary and not necessarily the variable you are trying to index on.
kk = min_id:max_id;
dataID=nan(size(kk));
for ii = 1:numel(kk)
ind=find(data(:,1) == kk(ii))
dataID(kk) = [ID(ind) ,DATE(ind) , Valeur(ind)]
end
This is better than indexing by min_id or max_id since it isn't clear that min_id starts at at 1 (maybe it starts at 0, or something else.)

Assigning times to events

include "globals.mzn";
%Data
time_ID = [11,12,13,14,15];
eventId = [0011, 0012, 0013, 0021, 0022, 0031, 0041, 0051, 0061, 0071];
int:ntime = 5;
int:nevent = 10;
set of int: events =1..nevent;
set of int: time = 1..ntime;
array[1..nevent] of int:eventId;
array[1..nevent] of var time:event_time;
array[1..ntime] of int:time_ID;
solve satisfy;
constraint
forall(event in eventId)(
exists(t in time_ID)(
event_time[event] = t ));
output[ show(event_time) ];
I'm trying to assign times to an event using the code above.
But rather than randomly assign times to the events, it returns an error " array access out of bounds"
How can I make it select randomly from the time array?
Thank you
The error was because you tried to assign the index 11 (the first element in eventId array) in "event_time" array.
The assigment of just 1's is correct since you haven't done any other constraints on the "event_time" array. If you set the number of solutions to - say - 3 you will see other solutions. And, in fact, the constraint as it stand now is not really meaningful since it just ensures that there is some assignment to the elements in "event_time", but this constraint is handled by the domain of "event_time" (i.e. that all indices are in the range 1..ntime).