Import Solution#

This is helpful if limitations prevent you from generating the solution internally.

This could be necessitated by things such as:

  • incompatibility in python version required for gana and solver

  • loading saved results to then update the model

An example pipeline would be:

  1. Use gana to generate .mps file in environment 1

  2. Generate a gurobi model in environment 2 from .mps using .read()

  3. Solve, and save solution as .pkl or .mps

  4. Load solution into gana model in environment 1 using import_solution

Take the diet problem for example#

In Environment 1#

# !pip install gana # uncomment and run to install Gana, if not in environment
from gana import Prg, I, V, P, inf

p = Prg()
p.item = I('milk', 'cheese', 'apples', tag='food item')
p.x = V(p.item, tag='amount of food item to intake')
p.protein = P(p.item, _=[40, 20, 10])
p.vitA = P(p.item, _=[5, 40, 30])
p.vitB = P(p.item, _=[20, 30, 40])
p.vitC = P(p.item, _=[30, 50, 60])
p.cost = P(p.item, _=[1, 2.5, 3 / 4])
p.cons_protein = sum(p.protein(i) * p.x(i) for i in p.item) >= 80
p.cons_vitA = sum(p.vitA(i) * p.x(i) for i in p.item) >= 60
p.cons_vitB = sum(p.vitB(i) * p.x(i) for i in p.item) >= 50
p.cons_vitC = sum(p.vitC(i) * p.x(i) for i in p.item) >= 30
p.obj_cost = inf(sum(p.cost(i) * p.x(i) for i in p.item))

Now that the problem is formulated, generate a .mps file

p.mps()
📝  Generated prog.mps                                                       ⏱ 0.0039 s

In Environment 2#

Read the .mps file in another environment. Optimize the generated model

import gurobipy as gp 
gm = gp.read('prog.mps')
gm.optimize()
Read MPS format model from file prog.mps
Reading time = 0.00 seconds
PROG: 4 rows, 3 columns, 12 nonzeros
Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (mac64[x86] - Darwin 21.6.0 21H1320)

CPU model: Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz
Thread count: 2 physical cores, 4 logical processors, using up to 4 threads

Optimize a model with 4 rows, 3 columns and 12 nonzeros
Model fingerprint: 0x7c6539af
Coefficient statistics:
  Matrix range     [5e+00, 6e+01]
  Objective range  [8e-01, 2e+00]
  Bounds range     [0e+00, 0e+00]
  RHS range        [3e+01, 8e+01]
Presolve time: 0.03s
Presolved: 4 rows, 3 columns, 12 nonzeros

Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0    0.0000000e+00   2.750000e+01   0.000000e+00      0s
       2    2.8695652e+00   0.000000e+00   0.000000e+00      0s

Solved in 2 iterations and 0.04 seconds (0.00 work units)
Optimal objective  2.869565217e+00

Save solution as JSON or pickle file The objective needs to be passed as a float as well

import pickle

with open("sol.pkl", "wb") as f:
    pickle.dump(([v.X for v in gm.getVars()], gm.ObjVal), f)

import json 

with open("sol.json", "w") as f:
    json.dump(([v.X for v in gm.getVars()], gm.ObjVal), f)

Back in Environment 1#

If using json

p.import_solution("sol.json")
📝  Generated Solution object for prog. See .solution                        ⏱ 0.0001 s

If using pickle

p.import_solution("sol.pkl")
📝  Generated Solution object for prog. See .solution                        ⏱ 0.0000 s

If both are loaded, it will just update them chronologically.

Recall that p.solution shows you the last updated solution

p.solutions
{0: Solution(name='prog_solution_0'), 1: Solution(name='prog_solution_1')}