import org.gnu.glpk.*;
public class Mip2 {

    @SuppressWarnings("empty-statement")
  public static void main(String[] arg)
  {
    glp_prob lp;
    glp_iocp iocp;
    SWIGTYPE_p_int ind;
    SWIGTYPE_p_double val;
    int ret;
    int rowcounter = 0;
    /*initial parameters*/

    double[] l = {40,50,100}; //length of comercial pieces
    double[] len = {10,5}; //length of demand pieces
    int[] demand = {4,6}; //quantity of each demand piece

    //important calculated constants

    int variables = (1+len.length)*l.length;
    int rows = l.length+len.length;

//  Create problem
    lp = GLPK.glp_create_prob();
    System.out.println("Problem created");
    GLPK.glp_set_prob_name(lp, "CuttingStock");

//  Define columns
    GLPK.glp_add_cols(lp, variables);
    int p = 0;
    for(int i = 0; i < l.length; i++) {
        for (int j = 0; j < len.length; j++ ) { 
            GLPK.glp_set_col_name(lp, ++p, "x("+i+","+j+")");
            GLPK.glp_set_col_kind(lp, p, GLPKConstants.GLP_IV);
            GLPK.glp_set_col_bnds(lp, p, GLPKConstants.GLP_LO, 0, 0);
        }
        GLPK.glp_set_col_name(lp, ++p, "u("+i+")");
        GLPK.glp_set_col_kind(lp,   p, GLPKConstants.GLP_BV);
    }

//  Create constraints
    GLPK.glp_add_rows(lp, rows);

// Constraints with the type len[0]*X1 + .... + len[0]*Xn <= l[0] * u[0]
    for(int i = 0;i < l.length; i++) {
        ind = GLPK.new_intArray(len.length + 2);
        val = GLPK.new_doubleArray(len.length + 2);
        for(int j = 0; j <= len.length; j++) {
            GLPK.intArray_setitem(ind, j+1, 1 + (len.length+1) * i + j);
            if (j==len.length) {
                GLPK.doubleArray_setitem(val, j+1, -l[i]);
            } else {
                GLPK.doubleArray_setitem(val, j+1, len[j]);
            }
        }
        GLPK.glp_set_row_name(lp, ++rowcounter, "Stock("+i+")");
        GLPK.glp_set_row_bnds(lp, rowcounter, GLPKConstants.GLP_UP, 
            0, 0);
        GLPK.glp_set_mat_row(lp, rowcounter, len.length+1, ind, val);
   }
// Constraints with the type X1 + .... + Xn <= cant[0]
    for(int j = 0; j < len.length; j++) {
        ind = GLPK.new_intArray(l.length + 1);
        val = GLPK.new_doubleArray(l.length + 1);
        for(int i = 0; i < l.length; i++) {
            GLPK.intArray_setitem(ind, i+1 , 1 + (len.length+1) * i + j);
            GLPK.doubleArray_setitem(val, i+1, 1.);
        }
        GLPK.glp_set_row_name(lp, ++rowcounter, "Demand("+j+")");
        GLPK.glp_set_row_bnds(lp, rowcounter, GLPKConstants.GLP_FX, 
            demand[j], 0);
        GLPK.glp_set_mat_row(lp, rowcounter, l.length, ind, val);
    }
   
//  Define objective
    GLPK.glp_set_obj_name(lp, "Waste");
    GLPK.glp_set_obj_dir(lp, GLPKConstants.GLP_MIN);

    p = 0;
    for(int i = 0; i < l.length; i++) {
        for(int j = 0; j <= len.length; j++) {
           if (j == len.length) {
               GLPK.glp_set_obj_coef(lp, ++p, l[i]);
           } else {
               GLPK.glp_set_obj_coef(lp, ++p, -len[j]);
           }
        }
    }


//  solve model
    iocp = new glp_iocp();
    GLPK.glp_init_iocp(iocp);
    iocp.setPresolve(GLPKConstants.GLP_ON);
    GLPK.glp_write_lp(lp, null, "cutting_stock.lp");
    ret = GLPK.glp_intopt(lp, iocp);


//  Retrieve solution
    if (ret == 0) {
      write_mip_solution(lp);
    }
    else {
      System.out.println("The problem could not be solved");
    }

    // free memory
    GLPK.glp_delete_prob(lp);
  }

  /**
   * write integer solution
   * @param mip problem
   */
  static void write_mip_solution(glp_prob lp)
  {
    int i;
    int n;
    String name;
    double val;

    name = GLPK.glp_get_obj_name(lp);
    val  = GLPK.glp_mip_obj_val(lp);
    System.out.print(name);
    System.out.print(" = ");
    System.out.println(val);
    n = GLPK.glp_get_num_cols(lp);
    for(i=1; i <= n; i++)
    {
      name = GLPK.glp_get_col_name(lp, i);
      val  = GLPK.glp_mip_col_val(lp, i);
      System.out.print(name);
      System.out.print(" = ");
      System.out.println(val);
    }
  }
}
