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"]