this repo has no description
1import contextlib
2import json
3import sys
4from ctypes.util import find_library
5
6import cffi
7
8DEBUG = False
9
10
11def debugprint(*args):
12 if DEBUG:
13 print(*args, file=sys.stderr, flush=True)
14
15
16ffi = cffi.FFI()
17ffi.cdef(
18 """
19 struct _MZNInstance;
20 typedef struct _MZNInstance* MZNInstance;
21
22 void set_rnd_seed(int seed);
23
24 MZNInstance minizinc_instance_init(const char* mza_file, const char* data_file, const char* solver);
25 void minizinc_instance_destroy(MZNInstance);
26
27 void minizinc_add_call(MZNInstance, const char* call, ...);
28 void minizinc_set_solution(MZNInstance, int def, int sol);
29 void minizinc_output_dict(MZNInstance, bool);
30 void minizinc_print_hedge(MZNInstance);
31 void minizinc_set_limit(MZNInstance, int limit);
32
33 void minizinc_push_state(MZNInstance);
34 void minizinc_pop_state(MZNInstance);
35
36 const char* minizinc_solve(MZNInstance);
37 """
38)
39# Set LD_LIBRARY_PATH (DYLD_LIBRARY_PATH on macOS) to the folder containing the mza library.
40lib = ffi.dlopen("mza")
41
42
43def set_rnd_seed(seed: int):
44 debugprint(f"set_rnd_seed({seed});")
45 lib.set_rnd_seed(seed)
46
47
48class Instance:
49 def __init__(self, mza_file, data_file, solver):
50 debugprint(
51 f'MZNInstance inst = minizinc_instance_init("{mza_file}", "{data_file}", "{solver}");'
52 )
53 self._ptr = lib.minizinc_instance_init(
54 mza_file.encode(), data_file.encode(), solver.encode()
55 )
56
57 def __del__(self):
58 debugprint(f"minizinc_instance_destroy(inst);")
59 lib.minizinc_instance_destroy(self._ptr)
60 self._ptr = None
61
62 def output_dict(self, b: bool):
63 debugprint(f"minizinc_output_dict(inst, {int(b)});")
64 lib.minizinc_output_dict(self._ptr, b)
65
66 def set_incumbent(self, sol):
67 for k, v in sol.items():
68 debugprint(f"minizinc_set_solution(inst, {k}, {v});")
69 lib.minizinc_set_solution(self._ptr, int(k), v)
70
71 def set_limit(self, limit):
72 debugprint(f"minizinc_set_limit(inst, {limit});")
73 lib.minizinc_set_limit(self._ptr, limit)
74
75 def print(self):
76 debugprint(f"minizinc_print_hedge(inst);")
77 lib.minizinc_print_hedge(self._ptr)
78
79 @contextlib.contextmanager
80 def branch(self):
81 try:
82 debugprint(f"minizinc_push_state(inst);")
83 lib.minizinc_push_state(self._ptr)
84 yield self
85 finally:
86 debugprint(f"minizinc_pop_state(inst);")
87 lib.minizinc_pop_state(self._ptr)
88
89 def add_call(self, call: str, *args):
90 debugprint(
91 f"minizinc_add_call(inst, \"{call}\"{''.join([', '+ str(i) for i in args])});"
92 )
93 lib.minizinc_add_call(
94 self._ptr, call.encode(), *[ffi.cast("int", i) for i in args]
95 )
96
97 def solve(self):
98 debugprint(f"minizinc_solve(inst);")
99 res = ffi.string(lib.minizinc_solve(self._ptr))
100 tmp = json.loads(res)
101 return tmp["status"], tmp["solution"]