//  File : pinfeas.java
//
//  Copyright : Copyright (c) MOSEK ApS, Denmark. All rights reserved.
//
//  Purpose: Demonstrates how to fetch a primal infeasibility certificate
//           for a linear problem
//
package com.mosek.example;
import mosek.*;

public class pinfeas {
  static double inf = 0.0; // Infinity for symbolic purposes

  // Set up a simple linear problem from the manual for test purposes
  public static mosek.Task testProblem() {
    mosek.Task task = new mosek.Task();
    task.appendvars(7);
    task.appendcons(7);
    task.putclist(new int[]{0,1,2,3,4,5,6}, new double[]{1,2,5,2,1,2,1});
    task.putaijlist(new int[]{0,0,1,1,2,2,2,3,3,4,5,5,6,6},
                    new int[]{0,1,2,3,4,5,6,0,4,1,2,5,3,6},
                    new double[]{1,1,1,1,1,1,1,1,1,1,1,1,1,1});
    mosek.boundkey up = mosek.boundkey.up,
                   fx = mosek.boundkey.fx,
                   lo = mosek.boundkey.lo;
    task.putconboundslice(0, 7, new mosek.boundkey[]{up,up,up,fx,fx,fx,fx},
                                new double[]{-inf, -inf, -inf, 1100, 200, 500, 500},
                                new double[]{200, 1000, 1000, 1100, 200, 500, 500});
    task.putvarboundsliceconst(0, 7, lo, 0, +inf);
    return task;
  }

  // Analyzes and prints infeasibility contributing elements
  // sl - dual values for lower bounds
  // su - dual values for upper bounds
  // eps - tolerance for when a nunzero dual value is significant
  public static void analyzeCertificate(double[] sl, double[] su, double eps) {
    for(int i = 0; i < sl.length; i++) {
      if (Math.abs(sl[i]) > eps)
        System.out.printf("#%d, lower,  dual = %e\n", i, sl[i]);
      if (Math.abs(su[i]) > eps)
        System.out.printf("#%d, upper,  dual = %e\n", i, su[i]);
    }
  }

  public static void main (String[] args) {
    // In this example we set up a simple problem
    // One could use any task or a task read from a file
    mosek.Task task = testProblem();

    // Useful for debugging
    task.writedata("pinfeas.ptf");                          // Write file in human-readable format
    // Attach a log stream printer to the task
    task.set_Stream(
      mosek.streamtype.log,
      new mosek.Stream()
    { public void stream(String msg) { System.out.print(msg); }});

    // Perform the optimization.
    task.optimize();
    task.solutionsummary(mosek.streamtype.log);

    // Check problem status, we use the interior point solution
    if (task.getprosta(soltype.itr) == prosta.prim_infeas) {
      // Set the tolerance at which we consider a dual value as essential
      double eps = 1e-7;

      System.out.println("Variable bounds important for infeasibility: ");
      analyzeCertificate(task.getslx(soltype.itr), task.getsux(soltype.itr), eps);
        
      System.out.println("Constraint bounds important for infeasibility: ");
      analyzeCertificate(task.getslc(soltype.itr), task.getsuc(soltype.itr), eps);
    }
    else {
      System.out.println("The problem is not primal infeasible, no certificate to show");
    }

    task.dispose();
  }
}
