Skip to content

Commit

Permalink
Merge branch 'xcsp3_executable' into exact_2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomSerg committed Jun 6, 2024
2 parents a5c7d1f + dfbd92b commit f7bdc68
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 17 deletions.
3 changes: 3 additions & 0 deletions cpmpy/expressions/globalconstraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -1262,8 +1262,11 @@ def decompose(self):
Principles and Practice of Constraint Programming–CP 2004: 10th International Conference, CP 2004
"""
from .python_builtins import any as cpm_any
from .variables import NDVarArray

args, precedence = self.args
if not isinstance(args, NDVarArray):
args = cpm_array(args)
constraints = []
for s,t in zip(precedence[:-1], precedence[1:]):
for j in range(len(args)):
Expand Down
20 changes: 14 additions & 6 deletions xcsp3/executable/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,10 @@ def ctr_precedence(self, lst: list[Variable], values: None | list[int], covered:
cpm_vars = self.get_cpm_vars(lst)
if values is None: # assumed to be ordered set of all values collected from domains in lst
lbs, ubs = get_bounds(cpm_vars)
values = sorted(range(min(lbs), max(lbs)+1))
values = set()
for lb, ub in zip(lbs, ubs):
values.update(list(range(lb, ub+1)))
values = sorted(values)

self.cpm_model += cp.Precedence(cpm_vars, values)

Expand Down Expand Up @@ -603,7 +606,7 @@ def ctr_binpacking(self, lst: list[Variable], sizes: list[int], condition: Condi
cpm_vars = self.get_cpm_vars(lst)
cpm_rhs = self.get_cpm_var(condition.right_operand())

for bin in range(1, len(cpm_vars)+1): # bin labeling starts at 1
for bin in range(0, len(cpm_vars)): # bin labeling starts at 0, contradicting the xcsp3 specification document?
self.cpm_model += self.eval_cpm_comp(cp.sum((cpm_array(cpm_vars) == bin) * sizes),
condition.operator,
cpm_rhs)
Expand All @@ -614,7 +617,7 @@ def ctr_binpacking_limits(self, lst: list[Variable], sizes: list[int], limits: l

for bin, lim in enumerate(limits):
self.cpm_model += eval_comparison("<=",
cp.sum((cpm_array(cpm_vars) == (bin+1)) * sizes), # bin labeling starts at 1
cp.sum((cpm_array(cpm_vars) == (bin)) * sizes),
lim)

def ctr_binpacking_loads(self, lst: list[Variable], sizes: list[int], loads: list[int] | list[Variable]):
Expand All @@ -625,7 +628,7 @@ def ctr_binpacking_loads(self, lst: list[Variable], sizes: list[int], loads: lis

for bin, load in enumerate(cpm_loads):
self.cpm_model += eval_comparison("==",
cp.sum((cpm_array(cpm_vars) == (bin + 1)) * sizes), # bin labeling starts at 1
cp.sum((cpm_array(cpm_vars) == (bin)) * sizes),
load)

def ctr_binpacking_conditions(self, lst: list[Variable], sizes: list[int], conditions: list[Condition]): # not in XCSP3-core
Expand Down Expand Up @@ -762,8 +765,13 @@ def get_cpm_exprs(self, lst):
if isinstance(lst[0], XVar):
return [self.get_cpm_var(x) for x in lst]
if isinstance(lst[0], range):
assert len(lst) == 1, "Expected range here, but got list with multiple elements, what's the semantics???"
return list(lst[0]) # this should work without converting to str first
# assert len(lst) == 1, f"Expected range here, but got list with multiple elements, what's the semantics???{lst}"

if len(lst) == 1:
return list(lst[0]) # this should work without converting to str first
else:
return [cp.intvar(l.start, l.stop-1) for l in lst]

# return list(eval(str(lst[0])))
else:
return self.exprs_from_node(lst)
Expand Down
16 changes: 8 additions & 8 deletions xcsp3/executable/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"minizinc": ["gecode", "chuffed"]
}
DEFAULT_SOLVER = "ortools"
TIME_BUFFER = 1 # seconds
TIME_BUFFER = 5 # seconds
# TODO : see if good value
MEMORY_BUFFER_SOFT = 2 # MB
MEMORY_BUFFER_HARD = 2 # MMB
Expand Down Expand Up @@ -237,9 +237,9 @@ def __post_init__(self):
self.dir = dir_path(self.dir)
if not is_supported_solver(self.solver):
raise(ValueError(f"solver:{self.solver} is not a supported solver. Options are: {str(SUPPORTED_SOLVERS)}"))
if self.subsolver is not None:
if not is_supported_subsolver(self.solver, self.subsolver):
raise(ValueError(f"subsolver:{self.subsolver} is not a supported subsolver for solver {self.solver}. Options are: {str(SUPPORTED_SUBSOLVERS[self.solver])}"))
# if self.subsolver is not None:
# if not is_supported_subsolver(self.solver, self.subsolver):
# raise(ValueError(f"subsolver:{self.subsolver} is not a supported subsolver for solver {self.solver}. Options are: {str(SUPPORTED_SUBSOLVERS[self.solver])}"))
self.benchdir = os.path.join(*(str(self.benchpath).split(os.path.sep)[:-1]))
self.benchname = str(self.benchpath).split(os.path.sep)[-1].split(".")[0]

Expand Down Expand Up @@ -398,7 +398,7 @@ def solver_arguments(args: Args, model:cp.Model):
def subsolver_arguments(args: Args, model:cp.Model):
if args.subsolver == "gecode": return gecode_arguments(args, model)
elif args.subsolver == "chuffed": return choco_arguments(args, model)
else: raise()
else: return {}

@contextmanager
def prepend_print():
Expand Down Expand Up @@ -526,9 +526,9 @@ def run_helper(args:Args):

# ------------------------------ Parse instance ------------------------------ #

start = time.time()
parse_start = time.time()
parser = ParserXCSP3(args.benchpath)
print_comment(f"took {(time.time() - start):.4f} seconds to parse XCSP3 model [{args.benchname}]")
print_comment(f"took {(time.time() - parse_start):.4f} seconds to parse XCSP3 model [{args.benchname}]")

# -------------------------- Configure XCSP3 parser callbacks -------------------------- #
start = time.time()
Expand Down Expand Up @@ -566,7 +566,7 @@ def run_helper(args:Args):
print_comment(f"took {tc.time:.4f} seconds to transfer model to {args.solver}")

# Solve model
time_limit = args.time_limit - tc.time - args.time_buffer if args.time_limit is not None else None
time_limit = args.time_limit - (time.time() - parse_start) - args.time_buffer if args.time_limit is not None else None

# If not time left
if time_limit is not None and time_limit <= 0:
Expand Down
11 changes: 8 additions & 3 deletions xcsp3/executable/test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def get_all_instances(instance_dir: os.PathLike, year:str):
cop_instance_types = ["COP", "MiniCOP"]
csp_instance_types = ["CSP", "MiniCSP"]

def instances(type, year) -> list:
def instances(type, year, filter) -> list:
"""
Filters and aggregates problem instances based on the provided `type`.
"""
Expand All @@ -103,9 +103,13 @@ def instances(type, year) -> list:
instances = get_all_instances(INSTANCES_DIR, year)["COP"]
else:
raise()


# return instances.keys(), instances.values()
return list(instances.items())
res = list(instances.items())
if filter is not None:
res = [i for i in res if filter in i[0]]
return res

def pytest_addoption(parser):
"""
Expand All @@ -124,6 +128,7 @@ def pytest_addoption(parser):
parser.addoption("--only_transform", action="store_true")
parser.addoption("--check", action="store_true")
parser.addoption("--year", action="store", default="2022")
parser.addoption("--filter", action="store", default=None)


def pytest_generate_tests(metafunc):
Expand All @@ -132,7 +137,7 @@ def pytest_generate_tests(metafunc):
"""

# Get the test instances based on the provided filter
instance = instances(type=metafunc.config.getoption("type"), year=metafunc.config.getoption("year"))
instance = instances(type=metafunc.config.getoption("type"), year=metafunc.config.getoption("year"), filter=metafunc.config.getoption("filter"))

# The test instances to solve
if "instance" in metafunc.fixturenames:
Expand Down

0 comments on commit f7bdc68

Please sign in to comment.