Saving associated best and worst LP solution for every node searched in the MILP?

Is it possible to save the best or worst LP solution in every node searched when a MILP is solved using GAMSPy?

I don’t understand. The node lp has exactly one solution, not a best or worst solution. Many GAMS[Py] solvers provide you with the solve trace that gives you the interval of dual bound and incumbent overt time. Perhaps, this is what you are looking for.

-Michael

Yes, thank you.

However, the documentation here states that in GAMSPy options that trace_file_format is a valid argument and option for solving the model. However, when executing the code, an error pops up.

Code:

b1.solve(output=sys.stdout, options=Options(trace_file_format=0, report_solution=1 ), solver_options={"reslim": "50"})

Error:

ValidationError: 1 validation error for Options
trace_file_format
  Extra inputs are not permitted [type=extra_forbidden, input_value=0, input_type=int]
    For further information visit https://errors.pydantic.dev/2.10/v/extra_forbidden

A closer look at the Options class doc (Options — GAMSPy documentation) shows that trace_file_format is indeed not a valid argument.

How do I implement this properly in GAMSPy?

Trace file is created automatically since GAMSPy 0.12.5. Apparently, we forgot to delete the option from documentation. Thanks for catching that but it’s not what you want to use. You should define the miptrace solver option (this option name can be different for other solvers). For example, let’s say you want to solve a dice model with XPRESS:

m = Container(working_directory=".")

f = Set(
    m,
    name="f",
    description="faces on a dice",
    records=[f"face{idx}" for idx in range(1, 7)],
)
dice = Set(
    m,
    name="dice",
    description="number of dice",
    records=[f"dice{idx}" for idx in range(1, 6)],
)

flo = Parameter(m, name="flo", description="lowest face value", records=1)
fup = Parameter(
    m, "fup", description="highest face value", records=len(dice) * len(f)
)

fp = Alias(m, name="fp", alias_with=f)

wnx = Variable(m, name="wnx", description="number of wins")
fval = Variable(
    m,
    name="fval",
    domain=[dice, f],
    description="face value on dice - may be fractional",
)
comp = Variable(
    m,
    name="comp",
    domain=[dice, f, fp],
    description="one implies f beats fp",
    type=VariableType.BINARY,
)

fval.lo[dice, f] = flo
fval.up[dice, f] = fup
fval.fx["dice1", "face1"] = flo

eq1 = Equation(m, "eq1", domain=dice, description="count the wins")
eq3 = Equation(
    m,
    "eq3",
    domain=[dice, f, fp],
    description="definition of non-transitive relation",
)
eq4 = Equation(
    m,
    "eq4",
    domain=[dice, f],
    description="different face values for a single dice",
)

eq1[dice] = Sum((f, fp), comp[dice, f, fp]) == wnx
eq3[dice, f, fp] = (
    fval[dice, f] + (fup - flo + 1) * (1 - comp[dice, f, fp])
    >= fval[dice.lead(1, type="circular"), fp] + 1
)
eq4[dice, f - 1] = fval[dice, f - 1] + 1 <= fval[dice, f]

xdice = Model(
    m,
    "xdice",
    equations=m.getEquations(),
    problem=Problem.MIP,
    sense=Sense.MAX,
    objective=wnx,
)
xdice.solve(solver="XPRESS", solver_options={"mipTrace": "my_trace.txt"})

You can check the same option for other solvers here: Solver Manuals

1 Like