##
#    Copyright: Copyright (c) MOSEK ApS, Denmark. All rights reserved.
#
#    File:    midual1.py
#
#    Purpose:  Demonstrates how to compute dual values with
#              respect to a fixed integer solution for a MIO problem.
#
#              minimize    500 s1 + 300 s2 + 10 x1 + 14 x2
#              subject to  x1 + x2 >= 100
#                          0 <= x1 <= 70 s1
#                          0 <= x2 <= 80 s2
#                          s1, s2 - binary
##

import sys
from mosek.fusion import *
import mosek.fusion.pythonic

# M is the initial mixed-integer model
with Model('midual1') as M:
  M.setLogHandler(sys.stdout)

  x = M.variable("x", 2, Domain.greaterThan(0))
  s = M.variable("s", 2, Domain.binary())

  M.objective(ObjectiveSense.Minimize, Expr.dot([10,14], x) + Expr.dot([500,300], s))

  M.constraint("demand", Expr.sum(x) == 100)
  M.constraint("production", x <= Expr.mulElm([70,80], s))

  M.solve()

  if M.getProblemStatus() != ProblemStatus.PrimalFeasible:
    raise Exception("Unsuitable problem status, exiting")

  print(f'Solution: x = {x.level()}')

  # F is the continuous fixed model
  with M.getFixedModel() as F:
    F.setLogHandler(sys.stdout)

    F.solve()

    if F.getProblemStatus() != ProblemStatus.PrimalAndDualFeasible:
      raise Exception("Unsuitable problem status, exiting")

    demand = F.getConstraint("demand")
    production = F.getConstraint("production")
    xfix = F.getVariable("x")

    print(f"xfix = {xfix.level()}")
    print(f"demand dual = {demand.dual()[0]}")
    print(f"production dual = {production.dual()}")
