Recursive if-then-else function

260 views
Skip to first unread message

Andrea Rendl-Pitrey

unread,
Apr 18, 2019, 1:13:10 PM4/18/19
to MiniZinc
Hi all,

I'm trying to achieve something like a "parameterized" if-the-else clause in a function. In particular, I would like to obtain if-clauses like the following, where the number if elseif clauses, the conditional expressions and the return values depend on a parameter:

function var float: p(var int: value) =

 
if value <= 0 then

   
0.01

 elseif value
<= 2 then

   
0.02

 elseif value
<= 4 then

   
0.5

 
else 0.01

 endif
;



So I tried to build the function p using a recursive if-then-else helper-function. I also "parameterise" the conditions and the return value:

set of float: returnValue = {0.01, 0.02, 0.5, 0.01};     % return values
 

function var float: p(var int: value) =
   let
{
     
set of int: bounds = { 0, 2, 4, 6};    % bounds for conditions
   
} in
   recursiveIf
(bounds, 1, value);

 

function var float: recursiveIf(set of int: bounds, int: index, var int: value) =

 
if value <= bounds[index] then
     
returnValue[index]

  elseif index
<= length(bounds) - 1 then
     recursiveIf
(bounds, index+1, value)

 
else
     
returnValue[index]

  endif
;

 
solve satisfy
;


When I run this piece of code in MiniZinc 2.2.3, I get the error message:

minizinc: /builds/minizinc/minizinc/lib/typecheck.cpp:833: MiniZinc::KeepAlive MiniZinc::addCoercion(MiniZinc::EnvI&, MiniZinc::Model*, MiniZinc::Expression*, const MiniZinc::Type&): Assertion `fi' failed.

I went to typecheck.cpp in the github repository on the master branch (which looks like it's the release branch), but could not find an assertion in line 833. And actually, I'm not even sure if my recursive if-then-else is semantically correct. It seems OK on paper, but not sure if I'm doing something really bad :-)

It would be great to hear if what I do is correct, and if it is possible to do what I would like to do with MiniZinc. If it isn't possible, then that's fine, I can also automatically generate the respective functions and append them to the model. I'd just rather have everything parameter-related in the data files, to keep things clean.

Thank you for your help!

Cheers,
Andrea

 

Peter Stuckey

unread,
Apr 19, 2019, 4:52:03 AM4/19/19
to mini...@googlegroups.com
Why not just

var int: ite(array[int] of var bool: c, array[int] of int: e) =
         e[arg_max(c)];

as long as the c array has a "true" as last argument then the arg_max returns the first Boolean which is true.

So

constraint  x <= ite([value <= 0, value <= 2,  value <= 4, true], [0.01, 0.02, 0.5, 0.01]);     

minizinc: /builds/minizinc/minizinc/lib/typecheck.cpp:833: MiniZinc::KeepAliveMiniZinc::addCoercion(MiniZinc::EnvI&, MiniZinc::Model*, MiniZinc::Expression*, const MiniZinc::Type&):Assertion `fi' failed.

I went to typecheck.cpp in the github repository on the master branch (which looks like it's the release branch), but could not find an assertion in line 833. And actually, I'm not even sure if my recursive if-then-else is semantically correct. It seems OK on paper, but not sure if I'm doing something really bad :-)

It would be great to hear if what I do is correct, and if it is possible to do what I would like to do with MiniZinc. If it isn't possible, then that's fine, I can also automatically generate the respective functions and append them to the model. I'd just rather have everything parameter-related in the data files, to keep things clean.

Thank you for your help!

Cheers,
Andrea

 

-- 
You received this message because you are subscribed to the Google Groups "MiniZinc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to minizinc+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/minizinc/635c1936-a2ed-4959-a556-0bd59a1f4ea6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andrea Rendl-Pitrey

unread,
Apr 19, 2019, 8:04:41 AM4/19/19
to mini...@googlegroups.com
Thank you, Peter, this is much neater! I managed to get the example to run with arg_max, but only for integer returnValues:

include "arg_max.mzn";

var 0..10: value;
set of int: returnValue = {1, 2, 50, 1};  % this set is now int
set of int: bound = { 0, 2, 4, 6};
	         	       
function var float: p(var int: value) = 
   ite([ value <= i | i in bound ], set2array(returnValue)); 

function var int: ite(array[int] of var bool: c, array[int] of int: e) = e[arg_max(c)];
         
solve maximize p(value);

However, when I try to solve it with float returnValues, as in my original problem, I get the same error message as I got with the recursive if-then-else function: 
minizinc: /builds/minizinc/minizinc/lib/typecheck.cpp:833: MiniZinc::KeepAlive MiniZinc::addCoercion(MiniZinc::EnvI&, MiniZinc::Model*, MiniZinc::Expression*, const MiniZinc::Type&): Assertion `fi' failed.

This is not a problem for me, since I can make a workaround with integer values, but there might be a bug or something in the library code. Here is the code that produces the error message, in case you are interested. Note that I had to write my own set2array function since MiniZinc currently does not provide set2array for float sets.

include "arg_max.mzn";

var 0..10: value;
set of float: returnValue = {0.01, 0.02, 0.5, 0.01}; % float set
set of int: bound = { 0, 2, 4, 6};
	         	        
function var float: p(var int: value) = 
   ite([ value <= i | i in bound ], mySet2array(returnValue)); 

function var float: ite(array[int] of var bool: c, array[int] of float: e) = e[arg_max(c)];

% primitive helper function to convert float set into float array
function set of float: mySet2array(set of float: mySet) = 
   let {
       set of int: mySetInt = { float2int(i*100) | i in mySet };
   }
   in [ i/100 | i in set2array(mySetInt) ]; % this is the built-in set2array, only for ints

solve maximize p(value);


Cheers,
Andrea


         

You received this message because you are subscribed to a topic in the Google Groups "MiniZinc" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/minizinc/KpG_7JrW5Hc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to minizinc+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/minizinc/DE4F107A-5FF8-436A-A80C-018CE90EDF18%40gmail.com.

Andrea Rendl-Pitrey

unread,
Apr 19, 2019, 8:52:00 AM4/19/19
to mini...@googlegroups.com
Actually, I think I found the source of the error, and it looks like a bug. The "Assertion `fi' failed."-error arises when accessing a set element of a float set. The following code produces the error:

set of float: floatSet = {0.1, 0.02, 0.3, 0.04};

var 0.0..10.0: x;
constraint x <= floatSet[2];

solve satisfy;

While the following code with an int set works:

set of int: intSet = {1,2,3,4};

var 0..10: y;
constraint y <= intSet[2];

solve satisfy;
Reply all
Reply to author
Forward
0 new messages