minizinc / minizinc-python Goto Github PK
View Code? Open in Web Editor NEWAccess to all MiniZinc functionality directly from Python
Home Page: https://minizinc-python.readthedocs.io/
License: Mozilla Public License 2.0
Access to all MiniZinc functionality directly from Python
Home Page: https://minizinc-python.readthedocs.io/
License: Mozilla Public License 2.0
Currently np.array are not supported as parameter of the model and generates TypeError: Object of type 'ndarray' is not JSON serializable
. But numpy is very popular and widely used library for working with arrays.
I think minizinc-python should support it, I would like to add this support, but before I want to ask what is the best way to do it:
What is the best choise?
Regards,
Artyom.
Hi all,
I create this issue to discuss the verbose
parameter.
I am feeding the solve
command with the following arguments:
cp_inst.solve(timeout=time_limit,
processes=self.num_of_threads,
verbose=True,
debug_output=Path("./debug_output.txt", intermediate_solutions=True),
optimisation_level=2)
My purpose is to see the solver's progress report on-the-fly through the terminal. This feature is available when we use Minizinc through the terminal. However, I could not find a configuration for this purpose in the Python interface. For example, the above configuration outputs the progress report when the running process terminates.
Is there any configuration to represent the solver's progress report on-the-fly through the terminal?
Hello all,
I would just like to report that we can not get the intermediate solution after a keyboard interruption.
However, this feature is available when we use Minizinc through the terminal to solve an optimization problem.
The current Python interface outputs the intermediate solution when the time limit reaches. So, is it possible to add this feature for the keyboard interruptions as well?
I have Ubuntu20 as OS and my python version is python3. When I try to import Instance from z3 using: import Instance from z3 , I get the following error :
ImportError: cannot import name 'Instance' from 'minizinc' (/home/maryam/.local/lib/python3.8/site-packages/minizinc/init.py)
Any idea?
Hello all,
I'd just like to inform you that the "timeout" parameter does not work correctly. More precisely, assuming that cp_inst
is a cp instance
object, I get the following error when I call its solve
method (cp_inst.solve(timeout=time_limit)
):
File "/.local/lib/python3.8/site-packages/minizinc/instance.py", line 117, in solve
return asyncio.run(coroutine)
File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/.local/lib/python3.8/site-packages/minizinc/CLI/instance.py", line 417, in solve_async
async for result in self.solutions(
File "/.local/lib/python3.8/site-packages/minizinc/CLI/instance.py", line 322, in solutions
cmd.extend(["--time-limit", str(int(timeout.total_seconds() * 1000))])
AttributeError: 'int' object has no attribute 'total_seconds'
We are using Anaconda and created an env called MENuS. We are trying to follow the example in the documentation: https://minizinc-python.readthedocs.io/en/latest/getting_started.html#installation (Windows)
Using Python infinity value in the MiniZinc data is encoded in JSON as "Infinity" instead of "infinity", which makes MiniZinc crash. I believe the best way would be to change MZNJSONEncoder to support that or forbid this conversion to happen.
Simple example:
`
from minizinc import Instance, Model, Solver
gecode = Solver.lookup("gecode")
model = Model()
model.add_string(
"""
enum DAY = {A,B,C,D};
array[1..2,1..2] of var DAY: res;
array[1..2,1..2] of var int: res2;
"""
)
instance = Instance(gecode, model)
result = instance.solve()`
res is a list of size 4
res2 is a list of two lists of size 2 (2x2)
I couldn't find where the conversion to python variables is done.
Hi,
Could you add to Solver a function to get the list of installed solvers?
I see the logic of getting the list of solves is in lookup(), but it is not exported. Furthermore, it contains entries not supported by the library (e.g. findMUS, according to a separate entry), which would ideally be filtered out?
Finally, it would be even better if that list could get further filtered to only the systems installed locally, e.g. that minizinc can run. I don't have cplex on this machine so ideally it would not be shown (perhaps detectable with the version being empty, or the executable?
Thanks in advance,
Tias
(I could also create a pull request, if you recommend what way is best to check whether a solver is supported on the local machine, and what to filter out from globalizer/findmus/api/...)
Hello,
Is there a function or a command or a flag
to be able to have the solutions (results) directly to json or dict
? Without having to indicate directly in the code which variables should be printed.
I have seen that the instance.output()
function generates a dictionary with the model variables and the dictionary can be obtained. But I wanted to see if there was a direct way.
import minizinc
from minizinc import Result, Solver, Instance
model = minizinc.Model()
model.add_string("""
int: n=4;
array [1..n] of var 1..n: q;
include "alldifferent.mzn";
constraint alldifferent(q);
constraint alldifferent(i in 1..n)(q[i] + i);
constraint alldifferent(i in 1..n)(q[i] - i);
""")
solver = Solver.lookup("gecode")
instance = Instance(solver, model)
result: Result = instance.solve()
print(result["q"]) # <------ no this way
print(result) # "Solution(q=[3, 1, 4, 2], _checker='')" <--- this is a string.
print(instance.output()) # {'q': typing.List[int], '_checker': <class 'str'>}
Hi all
I am using libminizinc
from my own library which also has a Python binding. The library is usually used from a python environment and sometimes in Jupyter.
I am now facing a runtime issue "RuntimeError: asyncio.run() cannot be called from a running event loop" which is well documented here and in the doc except that in my case %load_ext iminizinc
is not working for me as the location of the executable id dynamically resolved in my library and is not known from the user.
Any fix I could/should investigate from my side?
Thanks
How can we implement ['/Applications/MiniZincIDE.app/Contents/Resources/minizinc', '--solver', '[email protected]', '--named-only', ...]?
I can use the argument when using '/Applications/MiniZincIDE.app/Contents/Resources/bin/findMUS' instead but I was wondering if there is a cleaner way of doing so when running with '--solver', '[email protected]'.
I also found that in driver.py the solver configuration ( arg = ["--allow-multiple-assignments"]) causes an error when creating an instance of findMUS solver. In addition I found an issue in instance.py in: 'self._driver.run(["--model-interface-only"]' .
Am I doing something wrong or it is python Minizinc not ready for findMUS solver?
Hi,
I am a big minizinc fan, and so would first like to thank you for creating these python bindings to this amazing tool.
I guess the one thing left that is still holding me back from adopting minizinc as default modeling language, is the ability to get a low-level interface to the underlying solver. What I mean is to be able to do something like this:
model = Model("model.mzn")
gurobi = Solver.lookup("gurobi")
instance = Instance(gurobi, model)
guroby_py_model = instance.get_underlying_solver(gurobi) # < ----- this
The reason for this, is that then I am not locked in the current subset of functionality provided by minizinc for solving optimization problems. In the example, gurobi_py_model would have all the functionality available in gurobi official python version, which includes features like dynamically adding cuts, warm starts, heuristics, etc.
An integration like this seems to bring the best of both worlds: use minizinc for modelling which is where it excels, and then use solver library for fine tuning the solving process.
For the particular case of gurobi or other MIP solvers, it seems this would not be hard to accomplish: we would just need to add all constraints into a gurobipy.Model and return it. Or am I missing something?
I suppose that this is not something we could do for every solver because not every solver has a python interface.
Is this something you would consider adding to this library?
Thanks!
Marco
Hi,
I have my own custom solver that works with Minizinc but I am not trying to get it working with the Python interface. The Minizinc interface does not have '--intermediate-solutions' option but the I looked through the python interface codebase and saw that it is set as part of the standard command line arguments.
Unfortunately, even though my solver can generate intermediate-solutions, for some reason the python interface is not able to use that feature with my solver. I have tried commenting that line out locally and then verified that my solver is able to use the python interface!
Hence, I wanted to ask if it is possible to make that flag set based on a user-defined parameter instead of setting it by default?
I'm not sure if this is intended behaviour - but if you pass free_search=True
along to an instance whos solver does not support it a MiniZincError is thrown.
import minizinc as mz
solver = mz.Solver.lookup('coin-bc')
model = mz.Model()
model.add_string("var 1..10: a;")
instance = mz.Instance(solver, model)
solution = instance.solve(free_search=True)
It might be nicer for users that known unsupported command line arguments are not forwarded on to the minizinc, especially as experimenting with different solvers is common.
The workaround is to do something like:
solution = instance.solve(free_search='f' in solver.stdFlags and True)
An empty minizinc.EXE console opens everytime an instance is started. It also becomes the active window and perturbs tje user. Could there be a parameter to be able to not make it appear?
Hi there. I'm trying to run the basic example on my system (Windows 11, Python 3.10, MiniZinc 2.6.3).
The files are named nqueens.mzn
and example.py
. minizinc-python is installed through pip as required. MiniZinc is installed in the default path.
The following error is however returned:
minizinc.error.MiniZincError: MiniZinc stopped with a non-zero exit code, but did not output an error message.
Any solution? Thanks
Hi,
I've come across two issues in the following code:
minizinc-python/src/minizinc/result.py
Lines 97 to 107 in 953ea27
The first one is that the following error occurs: ValueError: could not convert string to float: '64.218 (1:04.218)'
. I believe that when the time is above a minute, this issue occurs. The time comes in as 64.218 (1:04.218)
and thus I think it should be rewritten something like this:
if tt is timedelta:
time_us = int(float(value) * 1000000)
stats[name] = timedelta(microseconds=time_us)
elif (tt is None and ("time" in name or "Time" in name)):
value = value.split(" ")[0]
time_us = int(float(value) * 1000000)
stats[name] = timedelta(microseconds=time_us)
Also, there is an issue with the "thousands separator". When the number is large enough (in the thousands), it comes in like this: "24,895,209", which gives me the following error: ValueError: invalid literal for int() with base 10: '24,895,209'
. So for my code to work I needed to change:
elif tt is not None:
stats[name] = tt(value)
to:
elif tt is not None:
if tt is int:
stats[name] = int(float(value.replace(",", "")))
else:
stats[name] = tt(value)
I think it simply has to do with my system's time and number format, but I don't want to dive too deep into it. Just wanted to let you know that these issues exist. Otherwise very happy with the Python package of MiniZinc 👌
We're using an Anaconda virtual environment and the Path is already configured but we are still getting this error. If we try to run it using solve_async(), it shows this:
This example is from the documentation: https://minizinc-python.readthedocs.io/en/latest/getting_started.html
As per title - passing optimisation_level=0
does not result in -O 0
being passed to the CLI.
Inside of CLI/instance.py under CLIInstance.solutions
I believe that
# Set compiler optimisation level if specified
if optimisation_level:
cmd.extend(["-O", str(optimisation_level)])
should be
# Set compiler optimisation level if specified
if optimisation_level is not None:
cmd.extend(["-O", str(optimisation_level)])
thanks for the great package!
Running the example from the README does not work for me.
Ubuntu 20.04.3 LTS
Python 3.8.10
MiniZinc 2.6.2
The error is:
/bin/python3 /home/ubuntu/workspace/minizinc.py
Traceback (most recent call last):
File "/home/ubuntu/workspace/minizinc.py", line 1, in <module>
import minizinc
File "/home/ubuntu/workspace/minizinc.py", line 4, in <module>
model = minizinc.Model()
AttributeError: partially initialized module 'minizinc' has no attribute 'Model' (most likely due to a circular import)
The standard JSONEncoder
that is used to create the JSON input for a MiniZinc model ensures that an IntEnum
is always represented using its integer representation: https://github.com/python/cpython/blob/3.9/Lib/json/encoder.py#L309-L313
Normally the JSON representation can be customised in the default
member function of MZNJSONEncoder
, but because IntEnum
inherits from int
, the representation is part of the base types of JSONEncoder
that is directly implemented in the encoder library (and a C backend)
This is incorrect as an input for a MiniZinc enum, where a JSON object {"e": "some_name"}
is expected and an integer will not be accepted.
workaround
A current workaround is to use an Enum
in Python, or to use the actual matching integers in the MiniZinc model.
possible solutions
The following solutions could be considered:
IntEnum
_intstr
function (both in the Python and C implementation): https://github.com/python/cpython/blob/3.9/Lib/json/encoder.py#L271The last solution seems more likely, as I'm currently unaware of a better JSON Encoder alternative and several attempts are the second method have failed.
I use MiniZinc 2.5.5 on Windows 10 and want to use CBC with parallelization. I'm not sure if MiniZinc is compiled with parallel CBC. Setting environment variable OMP_NUM_THREADS doesn't work. I can not find any way to hand over something like "-threads 4" for instance.
I have a parallel CBC version on my computer. But how to use this instead of the build in version?
What would be the best way to activate parallel solving with Python and MiniZinc.
Tried running this example.
from minizinc import Instance, Model, Result, Solver, Status
gecode = Solver.lookup("gecode")
m = Model()
m.add_string(
"""
array[1..4] of var 1..10: x;
var int: obj;
constraint obj = sum(x);
output ["\\(obj)"]
"""
)
inst = Instance(gecode, m)
res: Result = inst.solve()
print(res.solution)
while res.status == Status.SATISFIED:
with inst.branch() as child:
child.add_string(f"constraint obj > {res['obj']}")
res = child.solve()
if res.solution is not None:
print(res.solution)
Getting the following error:
MiniZincSyntaxError Traceback (most recent call last)
<ipython-input-1-3d132e8ee7f9> in <module>
19 with inst.branch() as child:
20 child.add_string(f"constraint obj > {res['obj']}")
---> 21 res = child.solve()
22 if res.solution is not None:
23 print(res.solution)
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\instance.py in solve(self, timeout, nr_solutions, processes, random_seed, all_solutions, intermediate_solutions, free_search, optimisation_level, **kwargs)
115 if sys.platform == "win32":
116 asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
--> 117 return asyncio.run(coroutine)
118 else:
119 if sys.platform == "win32":
F:\MyPrograms\anaconda3\lib\asyncio\runners.py in run(main, debug)
41 events.set_event_loop(loop)
42 loop.set_debug(debug)
---> 43 return loop.run_until_complete(main)
44 finally:
45 try:
F:\MyPrograms\anaconda3\lib\asyncio\base_events.py in run_until_complete(self, future)
581 raise RuntimeError('Event loop stopped before Future completed.')
582
--> 583 return future.result()
584
585 def stop(self):
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\CLI\instance.py in solve_async(self, timeout, nr_solutions, processes, random_seed, all_solutions, intermediate_solutions, free_search, optimisation_level, **kwargs)
423 free_search=free_search,
424 optimisation_level=optimisation_level,
--> 425 **kwargs,
426 ):
427 status = result.status
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\CLI\instance.py in solutions(self, timeout, nr_solutions, processes, random_seed, all_solutions, intermediate_solutions, free_search, optimisation_level, verbose, debug_output, **kwargs)
297 raise NotImplementedError("Solver does not support the -n flag")
298 cmd.extend(["-n", str(nr_solutions)])
--> 299 if "-a" in self._solver.stdFlags and self.method != Method.SATISFY:
300 cmd.append("-a")
301 # Set number of processes to be used
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\CLI\instance.py in method(self)
99 def method(self) -> Method:
100 if self._method is None:
--> 101 self.analyse()
102 assert self._method is not None
103 return self._method
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\CLI\instance.py in analyse(self)
182 with self.files() as files:
183 assert len(files) > 0
--> 184 output = self._driver.run(["--model-interface-only"] + files, self._solver)
185 interface = json.loads(
186 output.stdout
F:\MyPrograms\anaconda3\lib\site-packages\minizinc\CLI\driver.py in run(self, args, solver, timeout)
137 )
138 if output.returncode != 0:
--> 139 raise parse_error(output.stderr)
140 return output
141
MiniZincSyntaxError: C:\Users\surya\AppData\Local\Temp\mzn_fragment2awvqo2s.mzn:2.5-9:
array[1..4] of var 1..10: x;
^^^^^
Error: syntax error, unexpected array, expecting end of file
File fragment:
1: constraint obj > 4
2: array[1..4] of var 1..10: x;
^^^^^
3: var int: obj;
I have an error like this:
File "C:\AlexeyFolder\ProductOptimization\base_solver.py", line 360, in solve
async for res in self.instance.solutions(**self.run_parameters):
File "C:\Users\0F15~1.WIN\AppData\Local\pypoetry\Cache\virtualenvs\opti-bed-solvers-8romFmtb-py3.9\lib\site-packages\minizinc\CLI\instance.py", line 382, in solutions
solution, statistics = parse_solution(
File "C:\Users\0F15~1.WIN\AppData\Local\pypoetry\Cache\virtualenvs\opti-bed-solvers-8romFmtb-py3.9\lib\site-packages\minizinc\result.py", line 335, in parse_solution
tmp = json.loads(raw, enum_map=enum_map, cls=MZNJSONDecoder)
File "C:\Users\Администратор.WIN-GHJQMNTKAB5\AppData\Local\Programs\Python\Python39\lib\json\__init__.py", line 359, in loads
return cls(**kw).decode(s)
File "C:\Users\Администратор.WIN-GHJQMNTKAB5\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\Администратор.WIN-GHJQMNTKAB5\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 4 column 234 (char 49151)
To understand it, I tried to export raw from result.py:
raw_fail.zip
It seems that because of the time limit, the output of the solution by or-tools was interrupted in the middle.
Am I right? Is there anything you can do about it on your side?
Minizinc 2.6.0
minizinc package 0.4.2
or-tools 9.0.9048
Hey Yip, MiniZinc team,
I know we can do model.add_string().
I would like to change the objective of a model. If I use add_string(), it just adds the new solve entry and then complains that a model can not have two 'solve' entries.
Would there be a way for your API to detect this, and overwrite the previous solve? otherwise I will have to book-keep the solve entry myself, could be nicer behind the API?
I'm not sure how you handle that with inst.child(), the use case is similar (repeated solving with changing objective).
Thanks,
Tias
Hello :)
I am working on something with the library and I have followed the documentation to solve an instance using a time limit.
model = Model(f"CP/src/{model_name}.mzn") # Load model from the file
solver = Solver.lookup(solver_name) # Look for the configuration of gecode solver
instance = Instance(solver, model) # Create instance of the problem
instance.add_file(data_file) # Add the data to the instance
# Solve instance (set a timeout of 300000 miliseconds)
timeout = datetime.timedelta(milliseconds=300000)
result = instance.solve(timeout=timeout)
But still it raises the following error:
minizinc.error.MiniZincError: WARNING: the --time-out flag has recently been changed.The time-out is now provided in milliseconds instead of seconds
I am been checking carefully the source code but I cannot either check the problem of the source or of mine. I only know that the exception is raised on the Instance.solutions() method.
# Raise error if required
stderr = await read_stderr
if code != 0 or status == Status.ERROR:
raise parse_error(stderr)
if debug_output is not None:
debug_output.write_bytes(stderr)
I assume might be a problem about versions? I am using python 3.9.7 and minizinc python 0.9
I have two arrays,They all P1= ["get","list","create","update","patch","watch","delete","deletecollection"] and P2=["get","list"],
How to judge that the intersection of P1 and P2 is empty?
Can you help me write a complete example, because I just started to use the MiniZinc
Hi,
I'm using the minizinc/libminizinc tests to run with my own solver to have an additional test suite for the solver.
After some initial hickups this worked very well so far, adding ~450 more unit tests for the solver.
After changing from minizinc 2.5.5 to 2.6.0 I now recognized new behaviour that was triggered due to an update of minizinc-python
.
In the libminizinc/tests/requirements.txt
there is a dependency to the develop branch of minizinc-python
.
When I now execute the tests with my solver, I do get the following errors on some of the tests:
pytest -k globals_all_different_int_opt --driver=../../MiniZincIDE-2.6.0-bundle-linux-x86_64/bin
E AssertionError: expected one of
E
...
E but got
E
E !Error
E message: syntax error, unexpected ';'
E type: SyntaxError
Executing minizinc directly with my solver
minizinc --solver flatzingo spec/unit/globals/alldifferent/globals_all_different_int_opt.mzn
or with chuffed
minizinc --solver chuffed spec/unit/globals/alldifferent/globals_all_different_int_opt.mzn
doesn't show anything special and the output is the same.
Any idea what and where this ';' could come from ?
A reproduction of the error can be found in this github action here:
https://github.com/potassco/flatzingo/runs/5360589007?check_suite_focus=true
Thanks a lot in advance.
As per title:
The issue seems to be that newer minizinc versions have their solutions parsed through _parse_stream_obj
which does not call any of the logic contained in set_stat
I was able to get the expected behaviour by changing minizinc/CLI/instance.py
line 547
from
elif obj["type"] == "statistics":
statistics.update(obj["statistics"])
to
elif obj["type"] == "statistics":
for key,val in obj['statistics'].items():
set_stat(statistics, key, str(val))
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.