diff --git a/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/model.py b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/model.py new file mode 100644 index 0000000..e72e34c --- /dev/null +++ b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/model.py @@ -0,0 +1,104 @@ +import jijmodeling as jm + +def build_ip_formulation() -> jm.Problem: + """Create integer programming formulation for the arc-based flow problem. + + This model aligns with the ZPL (0-based) specification, formulating a + multi-commodity flow problem with integer scaling and big-M constraints. + + Sets: + - N = {0..n−1} + - A = {(i, j) | i ≠ j} + - T = {(k, i, j) | i ≠ j and k ≠ j} + + Parameters: + - n (int): Number of nodes. + - t (ndarray, shape (n, n)): Demand matrix, with zero diagonal. + - M (int): Big-M constant for capacity constraints. + - intscale (int): Integer scaling factor. + + Variables: + - x[i, j] ∈ {0, 1}: Binary arc selection variable. + - f[k, i, j] ∈ ℤ, 0..intscale·M: Flow of commodity k on arc (i, j). + - z ∈ ℤ, 0..intscale·M: Global upper bound on flow. + + Objective: + - Minimize z. + + Constraints: + - c1: ∀ i ∈ N: Σ_{j ≠ i} x[i, j] = 2 (out-degree = 2). + - c2: ∀ j ∈ N: Σ_{i ≠ j} x[i, j] = 2 (in-degree = 2). + - c11: ∀ (k, i), k ≠ i: + Σ_{j ≠ i} f[k, j, i] − Σ_{j ≠ i, j ≠ k} f[k, i, j] + = t[k, i]·intscale + - c14: ∀ (k, i, j), i ≠ j, k ≠ j: + f[k, i, j] ≤ M·intscale·x[i, j] + - c100: ∀ (i, j), i ≠ j: + Σ_{k ≠ j} f[k, i, j] ≤ z + + Returns: + jm.Problem: JijModeling problem instance with all variables, + objective, and constraints defined. + """ + # ---- Placeholders ---- + n = jm.Placeholder("n") + t = jm.Placeholder("t", ndim=2) # (n,n) + M = jm.Placeholder("M") + intscale = jm.Placeholder("intscale") + + # ---- Indices ---- + i = jm.Element("i", belong_to=(0, n)) + j = jm.Element("j", belong_to=(0, n)) + k = jm.Element("k", belong_to=(0, n)) + + # ---- Vars ---- + x = jm.BinaryVar("x", shape=(n, n), description="arc i->j selected") + f = jm.IntegerVar( + "f", shape=(n, n, n), + lower_bound=0, upper_bound=intscale * M, + description="flow of commodity k on arc i->j" + ) + z = jm.IntegerVar("z", lower_bound=0, upper_bound=intscale * M) + + # ---- Problem & Objective ---- + problem = jm.Problem("ip_formulation", sense=jm.ProblemSense.MINIMIZE) + problem += z + + # c1: ∀ i ∈ N : Σ_{j ≠ i} x[i,j] = 2 + problem += jm.Constraint( + "c1_outdeg_eq_2", + jm.sum([(j, j != i)], x[i, j]) == 2, + forall=[i] + ) + + # c2: ∀ j ∈ N : Σ_{i ≠ j} x[i,j] = 2 + problem += jm.Constraint( + "c2_indeg_eq_2", + jm.sum([(i, i != j)], x[i, j]) == 2, + forall=[j] + ) + + # c11: flow balance + problem += jm.Constraint( + "c11_flow_balance", + jm.sum([(j, j != i)], f[k, j, i]) + - jm.sum([(j, (j != i) & (j != k))], f[k, i, j]) + == t[k, i] * intscale, + forall=[k, (i, k != i)] + ) + + # c14: capacity bound + problem += jm.Constraint( + "c14_capacity_by_x", + f[k, i, j] <= M * intscale * x[i, j], + forall=[k, i, (j, (i != j) & (k != j))] + ) + + # c100: z upper bound on flow + problem += jm.Constraint( + "c100_z_upper_bounds_flow", + jm.sum([(k, k != j)], f[k, i, j]) <= z, + forall=[i, (j, i != j)] + ) + + return problem diff --git a/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/ommx_create.py b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/ommx_create.py new file mode 100644 index 0000000..a11ac8b --- /dev/null +++ b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/ommx_create.py @@ -0,0 +1,155 @@ +import os +import jijmodeling as jm +import glob +from ommx.artifact import ArtifactBuilder +from model import build_ip_formulation +from sol_reader import parse_solution_zfx + + +def _pick_solution_file(sol_dir: str, base: str) -> str | None: + """Pick first existing solution file for a basename.""" + candidates = [ + os.path.join(sol_dir, f"{base}.opt.sol"), + os.path.join(sol_dir, f"{base}.best.sol"), + os.path.join(sol_dir, f"{base}.bst.sol"), + os.path.join(sol_dir, f"{base}.sol"), + ] + for p in candidates: + if os.path.exists(p): + return p + return None + + +def batch_process( + sol_root: str = "../../solutions", + output_directory: str = "./ommx_output", +): + """ + Process instances from a QBench JSON file and corresponding solution files, + convert them into OMMX artifacts, and save them to the output directory. + + Parameters: + sol_root (str): Path to the root solutions directory. + output_directory (str): Path to save the generated .ommx files. + """ + os.makedirs(output_directory, exist_ok=True) + + problem = build_ip_formulation() + + processed_count = 0 + error_count = 0 + + # scan all sol_root's .sol file and get the base name. + sol_files = glob.glob(os.path.join(sol_root, "*.sol")) + bases = set() + for path in sol_files: + name = os.path.basename(path) + for suffix in [".opt.sol", ".best.sol", ".bst.sol", ".sol"]: + if name.endswith(suffix): + bases.add(name[: -len(suffix)]) + break + + print(f"Found {len(bases)} bases: {sorted(bases)}") + + def cut_matrix(t: list[list[int]], n: int) -> list[list[int]]: + if not (5 <= n <= 24): + raise ValueError("n must be between 5 and 24.") + return [row[:n] for row in t[:n]] + + your_t_0based = [ + [0, 24, 43, 23, 21, 41, 61, 21, 20, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 24, 19, 23, 0], + [0, 0, 0, 0, 21, 18, 39, 23, 0, 0, 40, 19, 64, 19, 17, 64, 80, 0, 0, 22, 24, 18, 19, 0], + [16, 0, 0, 20, 44, 0, 42, 22, 20, 0, 0, 23, 21, 0, 40, 21, 38, 97, 22, 17, 20, 37, 17, 20], + [42, 20, 18, 0, 40, 57, 43, 42, 0, 0, 19, 17, 0, 39, 0, 0, 22, 41, 0, 0, 17, 42, 40, 43], + [0, 0, 0, 40, 0, 83, 60, 0, 44, 0, 37, 60, 0, 40, 0, 0, 40, 19, 0, 39, 41, 17, 0, 0], + [60, 18, 0, 37, 18, 0, 21, 41, 23, 39, 0, 63, 60, 39, 0, 19, 0, 16, 16, 0, 0, 40, 0, 16], + [22, 0, 0, 0, 0, 0, 0, 61, 36, 80, 96, 19, 19, 41, 16, 0, 0, 0, 22, 0, 43, 0, 44, 22], + [0, 0, 20, 19, 17, 20, 40, 0, 0, 60, 61, 0, 20, 62, 20, 0, 0, 38, 0, 0, 0, 0, 24, 22], + [21, 22, 38, 0, 44, 20, 40, 39, 0, 36, 22, 21, 19, 39, 19, 0, 0, 21, 24, 16, 23, 21, 37, 0], + [0, 24, 23, 39, 20, 0, 0, 41, 0, 0, 0, 22, 0, 0, 44, 42, 22, 42, 22, 19, 20, 58, 18, 0], + [60, 57, 0, 0, 16, 0, 16, 37, 0, 0, 0, 44, 63, 0, 18, 0, 17, 18, 0, 0, 0, 100, 24, 23], + [0, 44, 44, 0, 23, 17, 39, 21, 0, 17, 40, 0, 24, 78, 17, 24, 20, 18, 0, 24, 24, 0, 20, 0], + [23, 16, 0, 0, 0, 23, 0, 0, 0, 0, 43, 58, 0, 0, 24, 60, 0, 0, 19, 0, 21, 0, 20, 0], + [44, 20, 0, 19, 21, 0, 39, 19, 0, 0, 0, 39, 22, 0, 0, 64, 24, 22, 0, 39, 0, 43, 42, 16], + [0, 60, 37, 18, 0, 0, 0, 20, 0, 41, 43, 16, 43, 24, 0, 0, 18, 18, 0, 44, 20, 0, 21, 37], + [0, 0, 23, 39, 0, 24, 40, 0, 37, 0, 40, 20, 44, 43, 0, 0, 0, 0, 0, 16, 0, 59, 0, 0], + [0, 42, 0, 0, 23, 24, 38, 19, 36, 0, 20, 60, 57, 0, 23, 40, 0, 0, 0, 16, 42, 0, 23, 0], + [0, 41, 36, 43, 23, 41, 17, 0, 38, 0, 0, 21, 21, 17, 16, 16, 39, 0, 22, 0, 21, 23, 16, 23], + [17, 0, 23, 23, 20, 0, 17, 58, 17, 0, 20, 0, 17, 24, 0, 0, 17, 42, 0, 58, 19, 22, 0, 24], + [42, 0, 16, 0, 43, 0, 24, 36, 0, 16, 24, 41, 41, 0, 24, 0, 0, 0, 0, 0, 56, 38, 63, 19], + [37, 23, 23, 0, 42, 16, 23, 76, 23, 0, 0, 24, 20, 41, 20, 24, 40, 23, 0, 0, 0, 39, 20, 0], + [43, 20, 17, 17, 0, 20, 19, 0, 80, 0, 0, 0, 40, 0, 40, 16, 19, 0, 0, 0, 18, 0, 17, 0], + [18, 20, 44, 40, 21, 18, 0, 20, 0, 0, 16, 24, 0, 0, 19, 18, 0, 17, 23, 0, 23, 44, 0, 42], + [44, 0, 0, 0, 62, 0, 17, 41, 0, 0, 0, 63, 0, 37, 22, 0, 20, 0, 0, 19, 57, 18, 38, 0], + ] + + for base in sorted(bases): + # from base to obtain n, such like network05 → n=5 + try: + n_str = "".join(ch for ch in base if ch.isdigit()) + n_val = int(n_str) if n_str else 5 + except Exception: + print(f"[{base}] Cannot parse n from base, skip.") + continue + + try: + instance_data = { + "n": n_val, + "t": cut_matrix(your_t_0based, n_val), + "M": 1000, + "intscale": 1000, + } + + interpreter = jm.Interpreter(instance_data) + ommx_instance = interpreter.eval_problem(problem) + + sol_path = _pick_solution_file(sol_root, base) + solution = None + if sol_path: + try: + print(f" → Evaluating solution: {sol_path}") + solution_dict = parse_solution_zfx(sol_path, n_val) + solution = ommx_instance.evaluate(solution_dict) + if ( + solution.feasible + and abs(solution.objective - solution_dict[0]) < 1e-6 + ): + print( + f" objective={solution.objective}, feasible={solution.feasible}" + ) + else: + print( + " ! Objective mismatch or infeasible; will save instance only." + ) + solution = None + except Exception as sol_err: + print(f" ! Solution evaluation failed: {sol_err}") + solution = None + + out_path = os.path.join(output_directory, f"{base}.ommx") + if os.path.exists(out_path): + os.remove(out_path) + + builder = ArtifactBuilder.new_archive_unnamed(out_path) + builder.add_instance(ommx_instance) + if solution is not None: + builder.add_solution(solution) + builder.build() + + print(f" ✓ Created: {out_path}") + print("-" * 50) + processed_count += 1 + + except Exception as e: + print(f"[{base}] Error: {e}") + print("-" * 50) + error_count += 1 + + print(f"Batch complete — processed: {processed_count}, errors: {error_count}") + + +if __name__ == "__main__": + batch_process( + sol_root="../../solutions", + output_directory="./ommx_output", + ) diff --git a/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/sol_reader.py b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/sol_reader.py new file mode 100644 index 0000000..31a5be9 --- /dev/null +++ b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/sol_reader.py @@ -0,0 +1,77 @@ +import re + +def parse_solution_zfx(file_path: str, n: int) -> dict[int, int]: + """Parse Jij solution (.sol) into {id: value} with strict z→f→x ordering. + + Order: + - id=0 : z + - id=1.. : f[k,i,j] (k=0..n-1, i=0..n-1, j=0..n-1) + - then: x[i,j] (i=0..n-1, j=0..n-1) + + Args: + file_path (str): Path to solution file + n (int): Number of nodes + + Returns: + dict[int,int]: {id: value} in z→f→x order + """ + z_val = None + f_vals = {} + x_vals = {} + + with open(file_path, "r") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + + # z + m = re.match(r"^z\s+([-+]?\d+\.?\d*)$", line) + if m: + z_val = int(m.group(1)) + continue + + # f#k#i#j + m = re.match(r"^f#(\d+)#(\d+)#(\d+)\s+([-+]?\d+\.?\d*)$", line) + if m: + k, i, j, val = ( + int(m.group(1)) - 1, + int(m.group(2)) - 1, + int(m.group(3)) - 1, + int(m.group(4)), + ) + f_vals[(k, i, j)] = val + continue + + # x#i#j + m = re.match(r"^x#(\d+)#(\d+)\s+([-+]?\d+\.?\d*)$", line) + if m: + i, j, val = int(m.group(1)) - 1, int(m.group(2)) - 1, int(m.group(3)) + x_vals[(i, j)] = val + continue + + if z_val is None: + raise ValueError("No z found in solution file.") + + # ---- Rebuild {id: value} ---- + sol_dict = {} + idx = 0 + + # z + sol_dict[idx] = z_val + idx += 1 + + # f[k,i,j], dictionary order + for k in range(n): + for i in range(n): + for j in range(n): + sol_dict[idx] = f_vals.get((k, i, j), 0.0) + idx += 1 + + # x[i,j], dictionary order + for i in range(n): + for j in range(n): + sol_dict[idx] = x_vals.get((i, j), 0.0) + idx += 1 + + return sol_dict diff --git a/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/test_model.ipynb b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/test_model.ipynb new file mode 100644 index 0000000..3c65e3f --- /dev/null +++ b/ommx_quantum_benchmarks/qoblib/08_network/models/integer_lp/test_model.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "5533a1a5-19e4-4206-a7f5-6fbeb897cdda", + "metadata": {}, + "outputs": [], + "source": [ + "import jijmodeling as jm\n", + "\n", + "def build_ip_formulation() -> jm.Problem:\n", + " \"\"\"Create integer programming formulation for the arc-based flow problem.\n", + "\n", + " This model aligns with the ZPL (0-based) specification, formulating a\n", + " multi-commodity flow problem with integer scaling and big-M constraints.\n", + "\n", + " Sets:\n", + " - N = {0..n−1}\n", + " - A = {(i, j) | i ≠ j}\n", + " - T = {(k, i, j) | i ≠ j and k ≠ j}\n", + "\n", + " Parameters:\n", + " - n (int): Number of nodes.\n", + " - t (ndarray, shape (n, n)): Demand matrix, with zero diagonal.\n", + " - M (int): Big-M constant for capacity constraints.\n", + " - intscale (int): Integer scaling factor.\n", + "\n", + " Variables:\n", + " - x[i, j] ∈ {0, 1}: Binary arc selection variable.\n", + " - f[k, i, j] ∈ ℤ, 0..intscale·M: Flow of commodity k on arc (i, j).\n", + " - z ∈ ℤ, 0..intscale·M: Global upper bound on flow.\n", + "\n", + " Objective:\n", + " - Minimize z.\n", + "\n", + " Constraints:\n", + " - c1: ∀ i ∈ N: Σ_{j ≠ i} x[i, j] = 2 (out-degree = 2).\n", + " - c2: ∀ j ∈ N: Σ_{i ≠ j} x[i, j] = 2 (in-degree = 2).\n", + " - c11: ∀ (k, i), k ≠ i:\n", + " Σ_{j ≠ i} f[k, j, i] − Σ_{j ≠ i, j ≠ k} f[k, i, j]\n", + " = t[k, i]·intscale\n", + " - c14: ∀ (k, i, j), i ≠ j, k ≠ j:\n", + " f[k, i, j] ≤ M·intscale·x[i, j]\n", + " - c100: ∀ (i, j), i ≠ j:\n", + " Σ_{k ≠ j} f[k, i, j] ≤ z\n", + "\n", + " Returns:\n", + " jm.Problem: JijModeling problem instance with all variables,\n", + " objective, and constraints defined.\n", + " \"\"\"\n", + " # ---- Placeholders ----\n", + " n = jm.Placeholder(\"n\")\n", + " t = jm.Placeholder(\"t\", ndim=2) # (n,n)\n", + " M = jm.Placeholder(\"M\")\n", + " intscale = jm.Placeholder(\"intscale\")\n", + "\n", + " # ---- Indices ----\n", + " i = jm.Element(\"i\", belong_to=(0, n))\n", + " j = jm.Element(\"j\", belong_to=(0, n))\n", + " k = jm.Element(\"k\", belong_to=(0, n))\n", + "\n", + " # ---- Vars ----\n", + " x = jm.BinaryVar(\"x\", shape=(n, n), description=\"arc i->j selected\")\n", + " f = jm.IntegerVar(\n", + " \"f\", shape=(n, n, n),\n", + " lower_bound=0, upper_bound=intscale * M,\n", + " description=\"flow of commodity k on arc i->j\"\n", + " )\n", + " z = jm.IntegerVar(\"z\", lower_bound=0, upper_bound=intscale * M)\n", + "\n", + " # ---- Problem & Objective ----\n", + " problem = jm.Problem(\"ip_formulation\", sense=jm.ProblemSense.MINIMIZE)\n", + " problem += z\n", + "\n", + " # c1: ∀ i ∈ N : Σ_{j ≠ i} x[i,j] = 2\n", + " problem += jm.Constraint(\n", + " \"c1_outdeg_eq_2\",\n", + " jm.sum([(j, j != i)], x[i, j]) == 2,\n", + " forall=[i]\n", + " )\n", + " \n", + " # c2: ∀ j ∈ N : Σ_{i ≠ j} x[i,j] = 2\n", + " problem += jm.Constraint(\n", + " \"c2_indeg_eq_2\",\n", + " jm.sum([(i, i != j)], x[i, j]) == 2,\n", + " forall=[j]\n", + " )\n", + "\n", + " # c11: flow balance\n", + " problem += jm.Constraint(\n", + " \"c11_flow_balance\",\n", + " jm.sum([(j, j != i)], f[k, j, i])\n", + " - jm.sum([(j, (j != i) & (j != k))], f[k, i, j])\n", + " == t[k, i] * intscale,\n", + " forall=[k, (i, k != i)]\n", + " )\n", + "\n", + " # c14: capacity bound\n", + " problem += jm.Constraint(\n", + " \"c14_capacity_by_x\",\n", + " f[k, i, j] <= M * intscale * x[i, j],\n", + " forall=[k, i, (j, (i != j) & (k != j))]\n", + " )\n", + "\n", + " # c100: z upper bound on flow\n", + " problem += jm.Constraint(\n", + " \"c100_z_upper_bounds_flow\",\n", + " jm.sum([(k, k != j)], f[k, i, j]) <= z,\n", + " forall=[i, (j, i != j)]\n", + " )\n", + "\n", + " return problem\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cc77aecb-7444-4ada-a553-3b6b9b8b23d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\\begin{array}{cccc}\\text{Problem:} & \\text{ip\\_formulation} & & \\\\& & \\min \\quad \\displaystyle z & \\\\\\text{{s.t.}} & & & \\\\ & \\text{c100\\_z\\_upper\\_bounds\\_flow} & \\displaystyle \\sum_{\\substack{k = 0\\\\k \\neq j}}^{n - 1} f_{k, i, j} \\leq z & \\forall i \\in \\left\\{0,\\ldots,n - 1\\right\\} \\forall j \\in \\left\\{j \\in \\left\\{0,\\ldots,n - 1\\right\\} \\mid i \\neq j \\right\\} \\\\ & \\text{c11\\_flow\\_balance} & \\displaystyle \\sum_{\\substack{j = 0\\\\j \\neq i}}^{n - 1} f_{k, j, i} - \\sum_{\\substack{j = 0\\\\j \\neq i \\land j \\neq k}}^{n - 1} f_{k, i, j} = t_{k, i} \\cdot intscale & \\forall k \\in \\left\\{0,\\ldots,n - 1\\right\\} \\forall i \\in \\left\\{i \\in \\left\\{0,\\ldots,n - 1\\right\\} \\mid k \\neq i \\right\\} \\\\ & \\text{c14\\_capacity\\_by\\_x} & \\displaystyle f_{k, i, j} \\leq M \\cdot intscale \\cdot x_{i, j} & \\forall k \\in \\left\\{0,\\ldots,n - 1\\right\\} \\forall i \\in \\left\\{0,\\ldots,n - 1\\right\\} \\forall j \\in \\left\\{j \\in \\left\\{0,\\ldots,n - 1\\right\\} \\mid i \\neq j \\land k \\neq j \\right\\} \\\\ & \\text{c1\\_outdeg\\_eq\\_2} & \\displaystyle \\sum_{\\substack{j = 0\\\\j \\neq i}}^{n - 1} x_{i, j} = 2 & \\forall i \\in \\left\\{0,\\ldots,n - 1\\right\\} \\\\ & \\text{c2\\_indeg\\_eq\\_2} & \\displaystyle \\sum_{\\substack{i = 0\\\\i \\neq j}}^{n - 1} x_{i, j} = 2 & \\forall j \\in \\left\\{0,\\ldots,n - 1\\right\\} \\\\\\text{{where}} & & & \\\\& x & 2\\text{-dim binary variable}& \\text{arc i->j selected}\\\\& z & 0\\text{-dim integer variable}\\\\ & & \\text{lower bound: }0 & \\\\ & & \\text{upper bound: }intscale \\cdot M & \\\\& f & 3\\text{-dim integer variable}& \\text{flow of commodity k on arc i->j}\\\\ & & \\text{lower bound: }0 & \\\\ & & \\text{upper bound: }intscale \\cdot M & \\\\\\end{array}$$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "problem = build_ip_formulation()\n", + "problem" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5931df18-ab64-4a0b-9828-1ff77eb60008", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- 準備資料 ----\n", + "\n", + "def cut_matrix(t: list[list[int]], n: int) -> list[list[int]]:\n", + " if not (1 <= n <= 24):\n", + " raise ValueError(\"n must be between 1 and 24.\")\n", + " return [row[:n] for row in t[:n]]\n", + " \n", + "n_val = 6\n", + "your_t_0based = [\n", + " [0, 24, 43, 23, 21, 41, 61, 21, 20, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 24, 19, 23, 0],\n", + " [0, 0, 0, 0, 21, 18, 39, 23, 0, 0, 40, 19, 64, 19, 17, 64, 80, 0, 0, 22, 24, 18, 19, 0],\n", + " [16, 0, 0, 20, 44, 0, 42, 22, 20, 0, 0, 23, 21, 0, 40, 21, 38, 97, 22, 17, 20, 37, 17, 20],\n", + " [42, 20, 18, 0, 40, 57, 43, 42, 0, 0, 19, 17, 0, 39, 0, 0, 22, 41, 0, 0, 17, 42, 40, 43],\n", + " [0, 0, 0, 40, 0, 83, 60, 0, 44, 0, 37, 60, 0, 40, 0, 0, 40, 19, 0, 39, 41, 17, 0, 0],\n", + " [60, 18, 0, 37, 18, 0, 21, 41, 23, 39, 0, 63, 60, 39, 0, 19, 0, 16, 16, 0, 0, 40, 0, 16],\n", + " [22, 0, 0, 0, 0, 0, 0, 61, 36, 80, 96, 19, 19, 41, 16, 0, 0, 0, 22, 0, 43, 0, 44, 22],\n", + " [0, 0, 20, 19, 17, 20, 40, 0, 0, 60, 61, 0, 20, 62, 20, 0, 0, 38, 0, 0, 0, 0, 24, 22],\n", + " [21, 22, 38, 0, 44, 20, 40, 39, 0, 36, 22, 21, 19, 39, 19, 0, 0, 21, 24, 16, 23, 21, 37, 0],\n", + " [0, 24, 23, 39, 20, 0, 0, 41, 0, 0, 0, 22, 0, 0, 44, 42, 22, 42, 22, 19, 20, 58, 18, 0],\n", + " [60, 57, 0, 0, 16, 0, 16, 37, 0, 0, 0, 44, 63, 0, 18, 0, 17, 18, 0, 0, 0, 100, 24, 23],\n", + " [0, 44, 44, 0, 23, 17, 39, 21, 0, 17, 40, 0, 24, 78, 17, 24, 20, 18, 0, 24, 24, 0, 20, 0],\n", + " [23, 16, 0, 0, 0, 23, 0, 0, 0, 0, 43, 58, 0, 0, 24, 60, 0, 0, 19, 0, 21, 0, 20, 0],\n", + " [44, 20, 0, 19, 21, 0, 39, 19, 0, 0, 0, 39, 22, 0, 0, 64, 24, 22, 0, 39, 0, 43, 42, 16],\n", + " [0, 60, 37, 18, 0, 0, 0, 20, 0, 41, 43, 16, 43, 24, 0, 0, 18, 18, 0, 44, 20, 0, 21, 37],\n", + " [0, 0, 23, 39, 0, 24, 40, 0, 37, 0, 40, 20, 44, 43, 0, 0, 0, 0, 0, 16, 0, 59, 0, 0],\n", + " [0, 42, 0, 0, 23, 24, 38, 19, 36, 0, 20, 60, 57, 0, 23, 40, 0, 0, 0, 16, 42, 0, 23, 0],\n", + " [0, 41, 36, 43, 23, 41, 17, 0, 38, 0, 0, 21, 21, 17, 16, 16, 39, 0, 22, 0, 21, 23, 16, 23],\n", + " [17, 0, 23, 23, 20, 0, 17, 58, 17, 0, 20, 0, 17, 24, 0, 0, 17, 42, 0, 58, 19, 22, 0, 24],\n", + " [42, 0, 16, 0, 43, 0, 24, 36, 0, 16, 24, 41, 41, 0, 24, 0, 0, 0, 0, 0, 56, 38, 63, 19],\n", + " [37, 23, 23, 0, 42, 16, 23, 76, 23, 0, 0, 24, 20, 41, 20, 24, 40, 23, 0, 0, 0, 39, 20, 0],\n", + " [43, 20, 17, 17, 0, 20, 19, 0, 80, 0, 0, 0, 40, 0, 40, 16, 19, 0, 0, 0, 18, 0, 17, 0],\n", + " [18, 20, 44, 40, 21, 18, 0, 20, 0, 0, 16, 24, 0, 0, 19, 18, 0, 17, 23, 0, 23, 44, 0, 42],\n", + " [44, 0, 0, 0, 62, 0, 17, 41, 0, 0, 0, 63, 0, 37, 22, 0, 20, 0, 0, 19, 57, 18, 38, 0],\n", + "]\n", + "\n", + "instance_data = {\n", + " \"n\": n_val,\n", + " \"t\": cut_matrix(your_t_0based, n_val),\n", + " \"M\": 1000,\n", + " \"intscale\": 1000,\n", + "}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "40cc7ee7-ff07-47b3-9d5b-1c98a9677a50", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "objective=101000.0, feasible=True\n" + ] + } + ], + "source": [ + "import ommx_pyscipopt_adapter as scip_ad\n", + "problem = build_ip_formulation()\n", + "ommx_instance = jm.Interpreter(instance_data).eval_problem(problem)\n", + "solution = scip_ad.OMMXPySCIPOptAdapter.solve(ommx_instance)\n", + "\n", + "print(f\"objective={solution.objective}, feasible={solution.feasible}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47de8dd9-3867-40b6-841b-1a53d8680907", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}