/*
   Copyright : Copyright (c) MOSEK ApS, Denmark. All rights reserved.

   File :      midual1.c

    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
*/

#include <stdio.h>
#include "mosek.h"

#define MOSEKCALL(_r,_call)  if ( (_r)==MSK_RES_OK ) (_r) = (_call)

static void MSKAPI printstr(void *handle,
                            const char str[])
{
  printf("%s", str);
} /* printstr */

static const char * midual1_ptf =
"Task midual1                                      \n"
"Objective                                         \n"
"    Minimize + 10 x1 + 14 x2 + 500 s1 + 300 s2    \n"
"Constraints                                       \n"
"    'demand' [100] + x1 + x2                      \n"
"    'production1' [-inf;0] + x1 - 70 s1           \n"
"    'production2' [-inf;0] + x2 - 80 s2           \n"
"Variables                                         \n"
"    x1 [0;+inf]                                   \n"
"    x2 [0;+inf]                                   \n"
"    s1 [0;1]                                      \n"
"    s2 [0;1]                                      \n"
"Integers                                          \n"
"    s1 s2                                         \n";

int main(int argc, char *argv[])
{
  MSKtask_t    task = NULL, fixTask = NULL;
  MSKprostae   prosta, fixProsta;
  MSKrescodee  r = MSK_RES_OK;

  /* The original mixed-integer problem */
  MOSEKCALL(r, MSK_maketask(NULL, 0, 0, &task));
  MOSEKCALL(r, MSK_linkfunctotaskstream(task, MSK_STREAM_LOG, NULL, printstr));
  MOSEKCALL(r, MSK_putintparam(task, MSK_IPAR_LOG_INCLUDE_SUMMARY, 1));
  MOSEKCALL(r, MSK_readptfstring(task, midual1_ptf));

  MOSEKCALL(r, MSK_optimize(task));

  MOSEKCALL(r, MSK_getprosta(task, MSK_SOL_ITG, &prosta));
  if (r == MSK_RES_OK && prosta != MSK_PRO_STA_PRIM_FEAS) {
    printf("Unsuitable problem status, exiting\n");
    return -1;
  }

  if (r == MSK_RES_OK) {
    double x[2];
    MOSEKCALL(r, MSK_getxxslice(task, MSK_SOL_ITG, 0, 2, x));
    printf("x = %.2f, %.2f\n", x[0], x[1]);
  }

  /* Create and solve the problem with fixed variables */
  MOSEKCALL(r, MSK_getfixedproblem(task, &fixTask));
  MOSEKCALL(r, MSK_linkfunctotaskstream(fixTask, MSK_STREAM_LOG, NULL, printstr));

  MOSEKCALL(r, MSK_optimize(fixTask));

  MOSEKCALL(r, MSK_getprosta(fixTask, MSK_SOL_BAS, &fixProsta));
  if (r == MSK_RES_OK && fixProsta != MSK_PRO_STA_PRIM_AND_DUAL_FEAS) {
    printf("Unsuitable problem status, exiting\n");
    return -1;
  }

  if (r == MSK_RES_OK) {
    double xfix[2], y[3];
    MOSEKCALL(r, MSK_getxxslice(fixTask, MSK_SOL_BAS, 0, 2, xfix));
    MOSEKCALL(r, MSK_getyslice(fixTask, MSK_SOL_BAS, 0, 3, y));
    printf("xfix = %.2f, %.2f\n", xfix[0], xfix[1]);
    printf("demand dual = %.2f\n", y[0]);
    printf("production dual = %.2f, %.2f\n", y[1], y[2]);
  }
  
  if (task) MSK_deletetask(&task);
  if (fixTask) MSK_deletetask(&fixTask);

  return r;
} 
