paolodragone / pymzn

A Python wrapper for the MiniZinc tool pipeline.
MIT License
55 stars 15 forks source link

ValueError is raised with pymzn but working with MinizincIDE #44

Open Deathn0t opened 4 years ago

Deathn0t commented 4 years ago

Hi,

I am trying to use the cbc solver through pymzn. I have two files LP.mzn, Fourier.dzn. These files are running properly when I use the Minizinc IDE but the error ValueError: Value '1' is not a float. is raised with pymzn.

Here is the full error stacktrace:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-ab7f17e63e19> in <module>
----> 1 solution=inf555.minizinc('LP.mzn','Fourier.dzn', solver=inf555.cbc, output_node='item')
      2 
      3 solution

~/Documents/lX/2019-2020/s1/INF555-ConDes/TD9/inf555.py in minizinc(mzn, include, *dzn_files, **kwargs)
     14 def minizinc(mzn, *dzn_files, include=".", **kwargs):
     15     """Solve using minizinc."""
---> 16     return minizn(mzn, *dzn_files, include=include, **kwargs)
     17 
     18 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/mzn/minizinc.py in minizinc(mzn, args, data, include, stdlib_dir, globals_dir, declare_enums, allow_multiple_assignments, keep, output_vars, output_base, output_mode, solver, timeout, two_pass, pre_passes, output_objective, non_unique, all_solutions, num_solutions, free_search, parallel, seed, rebase_arrays, keep_solutions, return_enums, *dzn_files, **kwargs)
    685         types=types, keep_solutions=keep_solutions, return_enums=return_enums
    686     )
--> 687     solns = parser.parse(proc)
    688     return solns
    689 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/mzn/output.py in parse(self, proc)
    243         logger.info('Started parsing solver output.')
    244         solns = Solutions(Queue(), keep=self.keep_solutions)
--> 245         self._collect(proc, solns)
    246         return solns
    247 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/mzn/output.py in _collect(self, proc, solns)
    247 
    248     def _collect(self, proc, solns):
--> 249         for soln in self._parse(proc):
    250             solns._queue.put(soln)
    251         logger.info('Solutions parsed: {}'.format(solns._queue.qsize()))

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/mzn/output.py in _parse(self, proc)
    261         parse_lines.send(None)
    262         for line in proc.readlines():
--> 263             soln = parse_lines.send(line)
    264             if soln is not None:
    265                 yield soln

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/mzn/output.py in _parse_lines(self)
    279                     soln = dzn2dict(
    280                         soln, rebase_arrays=self.rebase_arrays,
--> 281                         types=self.types, return_enums=self.return_enums
    282                     )
    283                 line = yield soln

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in dzn2dict(dzn, rebase_arrays, types, return_enums)
    585             var_type = var_types.get(var, None)
    586         assign[var] = parse_value(
--> 587             val, var_type=var_type, enums=enums, rebase_arrays=rebase_arrays
    588         )
    589 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in parse_value(val, var_type, enums, rebase_arrays)
    433     if 'dims' in var_type:
    434         return _parse_array(
--> 435             val, rebase_arrays=rebase_arrays, var_type=var_type, enums=enums
    436         )
    437 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array(val, rebase_arrays, var_type, enums, raise_errors)
    335             p_val = _parse_array_vals(
    336                 indices, vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
--> 337                 enums=enums, raise_errors=raise_errors
    338             )
    339         return p_val

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array_vals(indices, vals, rebase_arrays, vals_type, enums, raise_errors)
    360             indices[1:], vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
    361             enums=enums, raise_errors=raise_errors
--> 362         ) for i in idx_set}
    363 
    364     if rebase_arrays and list(idx_set)[0] == 1:

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in <dictcomp>(.0)
    360             indices[1:], vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
    361             enums=enums, raise_errors=raise_errors
--> 362         ) for i in idx_set}
    363 
    364     if rebase_arrays and list(idx_set)[0] == 1:

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array_vals(indices, vals, rebase_arrays, vals_type, enums, raise_errors)
    355             vals.pop(0), var_type=vals_type, enums=enums,
    356             raise_errors=raise_errors
--> 357         ) for i in idx_set}
    358     else:
    359         arr = {i: _parse_array_vals(

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in <dictcomp>(.0)
    355             vals.pop(0), var_type=vals_type, enums=enums,
    356             raise_errors=raise_errors
--> 357         ) for i in idx_set}
    358     else:
    359         arr = {i: _parse_array_vals(

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_val(val, var_type, enums, raise_errors)
    272 
    273     return _parse_val_basic_type(
--> 274         val, var_type=var_type, enums=enums, raise_errors=raise_errors
    275     )
    276 

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_val_basic_type(val, var_type, enums, raise_errors)
    154 
    155     if var_type['type'] == 'float':
--> 156         return _parse_float(val, raise_errors=raise_errors)
    157 
    158     if raise_errors:

~/opt/anaconda3/envs/dh/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_float(val, raise_errors)
    105         return float(val)
    106     if raise_errors:
--> 107         raise ValueError('Value \'{}\' is not a float.'.format(val))
    108     return None
    109 

ValueError: Value '1' is not a float.

The function inf555.minizinc is just a simple wrapper calling pymzn.minizinc:

def minizinc(mzn, *dzn_files, include=".", **kwargs):
    """Solve using minizinc."""
    return minizn(mzn, *dzn_files, include=include, **kwargs)

I call the solver with:

solution=inf555.minizinc('LP.mzn','Fourier.dzn', solver=inf555.cbc)

My LP.mzn file is:

include "matrix.mzn";

int: m;
int: n;
array[1..1, 1..n] of float: c;
array[1..m, 1..n] of float: A;
array[1..m, 1..1] of float: b;

array[1..n, 1..1] of var float: x;
array[1..m, 1..1] of var float: Ax;

constraint forall(i in 1..n)(x[i,1] >= 0.0);

constraint matrix_mult(A, x, Ax);

constraint matrix_geq(Ax, b);

var float: f = sum(i in 1..n)(c[1,i]*x[i,1]);

solve minimize f;

and finally my Fourier.dzn file is:

m = 9;
n = 5;

A = [|-1.0, 0.0, 0.0, 0.0, 0.0
     |0.0, -1.0, 0.0, 0.0, 0.0
     |0.0, 0.0, -1.0, 0.0, 0.0
     |1.0, 1.0, 1.0, 0.0, 0.0
     |-1.0, -1.0, -1.0, 0.0, 0.0
     |0.0, 20.0, 0.0, -2.0, 0.0
     |0.0, -20.0, 0.0, 2.0, 0.0
     |0.0, 0.0, 20.0, 0.0, -2.0
     |0.0, 0.0, -20.0, 0.0, 2.0
     |];

b = [|-1.0
     |-1.0
     |-1.0
     |2.0
     |-2.0
     |0.0
     |0.0
     |0.0
     |0.0
     |];

c = [|0, 0, 0, -1, 0|];

Thank you for your help!

paolodragone commented 4 years ago

Indeed the parser is expecting a floating point to look like 1.0 or 0.5, and refuses to parse a 1 (which is something I could fix). I wonder why this happens though. Have you tried a different solver (I'm assuming inf555.cbc is an instance of pymzn.solvers.CBC)? By the way which version of MiniZinc and PyMzn are you running?

Deathn0t commented 4 years ago

Thank you @paolodragone!

Yes, the solver is pymzn.solvers.CBC. I am not sure I can use other solvers because of the float and linear programming aspect of this problem.

For the versions:

the output when I run is:

Running LP.mzn, with additional data Fourier.dzn 
x = array2d(1..5, 1..1, [-0.0, 2.0, -0.0, 20.0, -0.0]);
Ax = array2d(1..9, 1..1, [0.0, -2.0, 0.0, 2.0, -2.0, -0.0, -0.0, -0.0, -0.0]);
----------
==========
Finished in 54msec

That is why I don't understand this parsing error, I don't see any '1' alone anywhere,.

vrvarma commented 4 years ago

I had the same issue with floating point numbers and interestingly it works with output_mode='json' For example this works. solns = pymzn.minizinc('a.mzn', 'a.dzn', solver=pymzn.cbc, output_mode='json')

Is there a fix for this coming soon?

atbradley commented 3 years ago

I'm encountering the same (or a similar) issue running the first example in section 2.2 of the MiniZinc Handbook (@vrvarma's workaround works for me):

sol = pymzn.minizinc(laplacemodel, solver=pymzn.cbc)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-24-01ebc87427a8> in <module>
----> 1 sol = pymzn.minizinc(laplacemodel, solver=pymzn.cbc)

/opt/tljh/user/lib/python3.7/site-packages/pymzn/mzn/minizinc.py in minizinc(mzn, args, data, include, stdlib_dir, globals_dir, declare_enums, allow_multiple_assignments, keep, output_vars, output_base, output_mode, solver, timeout, two_pass, pre_passes, output_objective, non_unique, all_solutions, num_solutions, free_search, parallel, seed, rebase_arrays, keep_solutions, return_enums, *dzn_files, **kwargs)
    685         types=types, keep_solutions=keep_solutions, return_enums=return_enums
    686     )
--> 687     solns = parser.parse(proc)
    688     return solns
    689 

/opt/tljh/user/lib/python3.7/site-packages/pymzn/mzn/output.py in parse(self, proc)
    243         logger.info('Started parsing solver output.')
    244         solns = Solutions(Queue(), keep=self.keep_solutions)
--> 245         self._collect(proc, solns)
    246         return solns
    247 

/opt/tljh/user/lib/python3.7/site-packages/pymzn/mzn/output.py in _collect(self, proc, solns)
    247 
    248     def _collect(self, proc, solns):
--> 249         for soln in self._parse(proc):
    250             solns._queue.put(soln)
    251         logger.info('Solutions parsed: {}'.format(solns._queue.qsize()))

/opt/tljh/user/lib/python3.7/site-packages/pymzn/mzn/output.py in _parse(self, proc)
    261         parse_lines.send(None)
    262         for line in proc.readlines():
--> 263             soln = parse_lines.send(line)
    264             if soln is not None:
    265                 yield soln

/opt/tljh/user/lib/python3.7/site-packages/pymzn/mzn/output.py in _parse_lines(self)
    279                     soln = dzn2dict(
    280                         soln, rebase_arrays=self.rebase_arrays,
--> 281                         types=self.types, return_enums=self.return_enums
    282                     )
    283                 line = yield soln

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in dzn2dict(dzn, rebase_arrays, types, return_enums)
    585             var_type = var_types.get(var, None)
    586         assign[var] = parse_value(
--> 587             val, var_type=var_type, enums=enums, rebase_arrays=rebase_arrays
    588         )
    589 

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in parse_value(val, var_type, enums, rebase_arrays)
    433     if 'dims' in var_type:
    434         return _parse_array(
--> 435             val, rebase_arrays=rebase_arrays, var_type=var_type, enums=enums
    436         )
    437 

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array(val, rebase_arrays, var_type, enums, raise_errors)
    335             p_val = _parse_array_vals(
    336                 indices, vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
--> 337                 enums=enums, raise_errors=raise_errors
    338             )
    339         return p_val

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array_vals(indices, vals, rebase_arrays, vals_type, enums, raise_errors)
    360             indices[1:], vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
    361             enums=enums, raise_errors=raise_errors
--> 362         ) for i in idx_set}
    363 
    364     if rebase_arrays and list(idx_set)[0] == 1:

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in <dictcomp>(.0)
    360             indices[1:], vals, rebase_arrays=rebase_arrays, vals_type=vals_type,
    361             enums=enums, raise_errors=raise_errors
--> 362         ) for i in idx_set}
    363 
    364     if rebase_arrays and list(idx_set)[0] == 1:

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_array_vals(indices, vals, rebase_arrays, vals_type, enums, raise_errors)
    355             vals.pop(0), var_type=vals_type, enums=enums,
    356             raise_errors=raise_errors
--> 357         ) for i in idx_set}
    358     else:
    359         arr = {i: _parse_array_vals(

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in <dictcomp>(.0)
    355             vals.pop(0), var_type=vals_type, enums=enums,
    356             raise_errors=raise_errors
--> 357         ) for i in idx_set}
    358     else:
    359         arr = {i: _parse_array_vals(

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_val(val, var_type, enums, raise_errors)
    272 
    273     return _parse_val_basic_type(
--> 274         val, var_type=var_type, enums=enums, raise_errors=raise_errors
    275     )
    276 

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_val_basic_type(val, var_type, enums, raise_errors)
    154 
    155     if var_type['type'] == 'float':
--> 156         return _parse_float(val, raise_errors=raise_errors)
    157 
    158     if raise_errors:

/opt/tljh/user/lib/python3.7/site-packages/pymzn/dzn/parse.py in _parse_float(val, raise_errors)
    105         return float(val)
    106     if raise_errors:
--> 107         raise ValueError('Value \'{}\' is not a float.'.format(val))
    108     return None
    109 

ValueError: Value '-0' is not a float.