From 374d9168c6c53453adc3b71446f41de845e896c1 Mon Sep 17 00:00:00 2001 From: ilansen Date: Thu, 19 Dec 2024 09:40:26 +1100 Subject: [PATCH 1/2] Add support for combining different diversity measures and constrainting them. --- src/minizinc/helpers.py | 24 +++++++++++++++++++++--- src/minizinc/instance.py | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/minizinc/helpers.py b/src/minizinc/helpers.py index 159ba2c..cd3f29d 100644 --- a/src/minizinc/helpers.py +++ b/src/minizinc/helpers.py @@ -162,10 +162,11 @@ def _add_diversity_to_opt_model( def _add_diversity_to_div_model( inst: minizinc.Instance, vars: List[Dict[str, Any]], - obj_sense: str, + div_anns: Dict[str, Any], gap: Union[int, float], sols: Dict[str, Any], ): + # Add the 'previous solution variables' for var in vars: # Current and previous variables @@ -190,6 +191,22 @@ def _add_diversity_to_div_model( f"array [1..{len(prevsol)}] of var {varprevtype}: dist_{varname} :: output = [{distfun}({varname}, {varprevname}[sol,{dotdots}]) | sol in 1..{len(prevsol)}];\n" ) + # Add minimum distance to the diversity distance measurement in the model code + if var["lb"] != "infinity": + inst.add_string( + f"constraint forall(sol in 1..{len(prevsol)})( dist_{varname}[sol] >= {var['lb']});" + ) + + # Add maximum distance to the diversity distance measurement in the model code + if var["ub"] != "infinity": + inst.add_string( + f"constraint forall(sol in 1..{len(prevsol)})( dist_{varname}[sol] <= {var['ub']});" + ) + + obj_sense = div_anns["objective"]["sense"] + aggregator = div_anns["aggregator"] if div_anns["aggregator"] != "" else "sum" + combinator = div_anns["combinator"] if div_anns["combinator"] != "" else "sum" + # Add the bound on the objective. if obj_sense == "-1": inst.add_string(f"constraint div_orig_objective <= {gap};\n") @@ -197,8 +214,9 @@ def _add_diversity_to_div_model( inst.add_string(f"constraint div_orig_objective >= {gap};\n") # Add new objective: maximize diversity. - dist_sum = "+".join([f'sum(dist_{var["name"]})' for var in vars]) - inst.add_string(f"solve maximize {dist_sum};\n") + div_combinator = ", ".join([f'{var["coef"]} * dist_{var["name"]}[sol]' for var in vars]) + dist_total = f"{aggregator}([{combinator}([{div_combinator}]) | sol in 1..{len(prevsol)}])" + inst.add_string(f"solve maximize {dist_total};\n") return inst diff --git a/src/minizinc/instance.py b/src/minizinc/instance.py index 54f1572..ecf7859 100644 --- a/src/minizinc/instance.py +++ b/src/minizinc/instance.py @@ -392,7 +392,7 @@ async def diverse_solutions( child = _add_diversity_to_div_model( child, variables, - obj_anns["sense"], + div_anns, max_gap, prev_solutions, ) From 5b2055fa94749f1b865e9bfa8311407b200a2f22 Mon Sep 17 00:00:00 2001 From: "Jip J. Dekker" Date: Thu, 30 Jan 2025 10:23:07 +1100 Subject: [PATCH 2/2] Fix formatting --- src/minizinc/helpers.py | 13 +++++++++---- src/minizinc/instance.py | 8 +++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/minizinc/helpers.py b/src/minizinc/helpers.py index cd3f29d..121cc08 100644 --- a/src/minizinc/helpers.py +++ b/src/minizinc/helpers.py @@ -166,7 +166,6 @@ def _add_diversity_to_div_model( gap: Union[int, float], sols: Dict[str, Any], ): - # Add the 'previous solution variables' for var in vars: # Current and previous variables @@ -204,8 +203,12 @@ def _add_diversity_to_div_model( ) obj_sense = div_anns["objective"]["sense"] - aggregator = div_anns["aggregator"] if div_anns["aggregator"] != "" else "sum" - combinator = div_anns["combinator"] if div_anns["combinator"] != "" else "sum" + aggregator = ( + div_anns["aggregator"] if div_anns["aggregator"] != "" else "sum" + ) + combinator = ( + div_anns["combinator"] if div_anns["combinator"] != "" else "sum" + ) # Add the bound on the objective. if obj_sense == "-1": @@ -214,7 +217,9 @@ def _add_diversity_to_div_model( inst.add_string(f"constraint div_orig_objective >= {gap};\n") # Add new objective: maximize diversity. - div_combinator = ", ".join([f'{var["coef"]} * dist_{var["name"]}[sol]' for var in vars]) + div_combinator = ", ".join( + [f'{var["coef"]} * dist_{var["name"]}[sol]' for var in vars] + ) dist_total = f"{aggregator}([{combinator}([{div_combinator}]) | sol in 1..{len(prevsol)}])" inst.add_string(f"solve maximize {dist_total};\n") diff --git a/src/minizinc/instance.py b/src/minizinc/instance.py index ecf7859..3584452 100644 --- a/src/minizinc/instance.py +++ b/src/minizinc/instance.py @@ -342,9 +342,11 @@ async def diverse_solutions( with inst.branch() as child: # Add constraints to the model that sets the decision variables to the reference solution, if provided if reference_solution: - if isinstance(reference_solution, Result) and is_dataclass( - reference_solution.solution - ) and not isinstance(reference_solution.solution, type): + if ( + isinstance(reference_solution, Result) + and is_dataclass(reference_solution.solution) + and not isinstance(reference_solution.solution, type) + ): solution_obj = asdict(reference_solution.solution) else: assert isinstance(reference_solution, dict)