com.joptimizer.optimizers.LPPresolverNetlibTest.java Source code

Java tutorial

Introduction

Here is the source code for com.joptimizer.optimizers.LPPresolverNetlibTest.java

Source

/*
 * Copyright 2011-2016 joptimizer.com
 *
 * This work is licensed under the Creative Commons Attribution-NoDerivatives 4.0 
 * International License. To view a copy of this license, visit 
 *
 *        http://creativecommons.org/licenses/by-nd/4.0/ 
 *
 * or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
 */
package com.joptimizer.optimizers;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;

import cern.colt.matrix.DoubleMatrix1D;
import cern.colt.matrix.DoubleMatrix2D;
import cern.colt.matrix.impl.SparseDoubleMatrix2D;

import com.joptimizer.algebra.QRSparseFactorization;
import com.joptimizer.util.Utils;

/**
 * LP presolving test.
 * 
 * @author alberto trivellato (alberto.trivellato@gmail.com)
 */
public class LPPresolverNetlibTest extends TestCase {
    private Log log = LogFactory.getLog(this.getClass().getName());

    /**
     * Tests the presolving of the afiro netlib problem.
     */
    public void testAfiro() throws Exception {
        log.debug("testAfiro");
        String problemName = "afiro";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the agg netlib problem.
     */
    public void testAgg() throws Exception {
        log.debug("testAgg");
        String problemName = "agg";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the blend netlib problem.
     */
    public void testBlend() throws Exception {
        log.debug("testBlend");
        String problemName = "blend";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the brandy netlib problem.
     */
    public void testBrandy() throws Exception {
        log.debug("testBrandy");
        String problemName = "brandy";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the degen2 netlib problem.
     * This fails because of the degenerate A matrix.
     */
    public void xxxtestDegen2() throws Exception {
        log.debug("testDegen2");
        String problemName = "degen2";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the etamacro netlib problem.
     */
    public void testEtamacro() throws Exception {
        log.debug("testEtamacro");
        String problemName = "etamacro";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the fit1d netlib problem.
     */
    public void testFit1d() throws Exception {
        log.debug("testFit1d");
        String problemName = "fit1d";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the israel netlib problem.
     */
    public void testIsrael() throws Exception {
        log.debug("testIsrael");
        String problemName = "israel";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the kb2 netlib problem.
     */
    public void testKb2() throws Exception {
        log.debug("testKb2");
        String problemName = "kb2";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the maros netlib problem.
     */
    public void testMaros() throws Exception {
        log.debug("testMaros");
        String problemName = "maros";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the pilot4 netlib problem.
     */
    public void testPilot4() throws Exception {
        log.debug("testPilot4");
        String problemName = "pilot4";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the afiro netlib problem.
     * @TODO: this fails!!!!
     */
    public void testRecipe() throws Exception {
        log.debug("testRecipe");
        String problemName = "recipe";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the sc50a netlib problem.
     */
    public void testSc50a() throws Exception {
        log.debug("testSc50a");
        String problemName = "sc50a";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the sc50b netlib problem.
     */
    public void testSc50b() throws Exception {
        log.debug("testSc50b");
        String problemName = "sc50b";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the scorpion netlib problem.
     */
    public void testScorpion() throws Exception {
        log.debug("testScorpion");
        String problemName = "scorpion";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the sctap1 netlib problem.
     * NB: this is a deterministic problem
     */
    public void testSctap1() throws Exception {
        log.debug("testSctap1");
        String problemName = "sctap1";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the share1b netlib problem.
     */
    public void testShare1b() throws Exception {
        log.debug("testShare1b");
        String problemName = "share1b";
        doTesting(problemName, true, 5.0E-5);//a lot of removeDuplicateRow, hence a loss of accuracy
    }

    /**
     * Tests the presolving of the ship04s netlib problem.
     */
    public void testShip04s() throws Exception {
        log.debug("testShip04s");
        String problemName = "ship04s";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the shell netlib problem.
     */
    public void testShell() throws Exception {
        log.debug("testShell");
        String problemName = "shell";
        doTesting(problemName);
    }

    /**
     * Tests the presolving of the ship08l netlib problem.
     */
    public void testShip08l() throws Exception {
        log.debug("testShip08l");
        String problemName = "ship08l";
        doTesting(problemName);
    }

    public void doTesting(String problemName) throws Exception {
        doTesting(problemName, true, Double.NaN);
    }

    /**
     * Tests the presolving of a netlib problem.
     * If checkExpectedSolution, the presolving is checked step by step against 
     * a (beforehand) known solution of the problem. 
     * NOTE: this known solution might differ from the solution given by the presolver 
     * (e.g. in the presence of a weakly dominated column @see {@link LPPresolver#removeDominatedColumns}, 
     * or if it is calculated with simplex method 
     * or if bounds are not exactly the same), so sometimes it is not a good test. 
     */
    public void doTesting(String problemName, boolean checkExpectedSolution, double myExpectedTolerance)
            throws Exception {
        log.debug("doTesting: " + problemName);

        int s = (int) Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator + problemName
                + File.separator + "standardS.txt")[0];
        double[] c = Utils.loadDoubleArrayFromFile(
                "lp" + File.separator + "netlib" + File.separator + problemName + File.separator + "standardC.txt");
        double[][] A = Utils.loadDoubleMatrixFromFile(
                "lp" + File.separator + "netlib" + File.separator + problemName + File.separator + "standardA.csv",
                ",".charAt(0));
        double[] b = Utils.loadDoubleArrayFromFile(
                "lp" + File.separator + "netlib" + File.separator + problemName + File.separator + "standardB.txt");
        double[] lb = Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator + problemName
                + File.separator + "standardLB.txt");
        double[] ub = Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator + problemName
                + File.separator + "standardUB.txt");
        double[] expectedSolution = Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator
                + problemName + File.separator + "standardSolution.txt");
        double expectedValue = Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator
                + problemName + File.separator + "standardValue.txt")[0];
        double expectedTolerance = Utils.loadDoubleArrayFromFile("lp" + File.separator + "netlib" + File.separator
                + problemName + File.separator + "standardTolerance.txt")[0];

        //in order to compare with tha Math results, we must have the same bounds
        for (int i = 0; i < lb.length; i++) {
            if (Double.isNaN(lb[i])) {
                lb[i] = -9999999d; //the same as the notebook value
            }
        }
        for (int i = 0; i < ub.length; i++) {
            if (Double.isNaN(ub[i])) {
                ub[i] = +9999999d; //the same as the notebook value
            }
        }

        RealMatrix AMatrix = MatrixUtils.createRealMatrix(A);
        RealVector bVector = MatrixUtils.createRealVector(b);
        //expectedTolerance = Math.max(expectedTolerance,   AMatrix.operate(MatrixUtils.createRealVector(expectedSolution)).subtract(bVector).getNorm());
        expectedTolerance = Math.max(1.e-9, expectedTolerance);

        // must be: A pXn with rank(A)=p < n
        QRSparseFactorization qr = new QRSparseFactorization(new SparseDoubleMatrix2D(A));
        qr.factorize();
        log.debug("p        : " + AMatrix.getRowDimension());
        log.debug("n        : " + AMatrix.getColumnDimension());
        log.debug("full rank: " + qr.hasFullRank());

        LPPresolver lpPresolver = new LPPresolver();
        lpPresolver.setNOfSlackVariables((short) s);
        if (checkExpectedSolution) {
            lpPresolver.setExpectedSolution(expectedSolution);// this is just for test!
            lpPresolver.setExpectedTolerance(myExpectedTolerance);// this is just for test!
        }
        // lpPresolver.setAvoidFillIn(true);
        // lpPresolver.setZeroTolerance(1.e-13);
        lpPresolver.presolve(c, A, b, lb, ub);
        int n = lpPresolver.getPresolvedN();
        DoubleMatrix1D presolvedC = lpPresolver.getPresolvedC();
        DoubleMatrix2D presolvedA = lpPresolver.getPresolvedA();
        DoubleMatrix1D presolvedB = lpPresolver.getPresolvedB();
        DoubleMatrix1D presolvedLb = lpPresolver.getPresolvedLB();
        DoubleMatrix1D presolvedUb = lpPresolver.getPresolvedUB();
        DoubleMatrix1D presolvedYlb = lpPresolver.getPresolvedYlb();
        DoubleMatrix1D presolvedYub = lpPresolver.getPresolvedYub();
        DoubleMatrix1D presolvedZlb = lpPresolver.getPresolvedZlb();
        DoubleMatrix1D presolvedZub = lpPresolver.getPresolvedZub();
        log.debug("n  : " + n);
        if (log.isDebugEnabled() && n > 0) {
            log.debug("presolvedC  : " + ArrayUtils.toString(presolvedC.toArray()));
            log.debug("presolvedA  : " + ArrayUtils.toString(presolvedA.toArray()));
            log.debug("presolvedB  : " + ArrayUtils.toString(presolvedB.toArray()));
            log.debug("presolvedLb : " + ArrayUtils.toString(presolvedLb.toArray()));
            log.debug("presolvedUb : " + ArrayUtils.toString(presolvedUb.toArray()));
            log.debug("presolvedYlb: " + ArrayUtils.toString(presolvedYlb.toArray()));
            log.debug("presolvedYub: " + ArrayUtils.toString(presolvedYub.toArray()));
            log.debug("presolvedZlb: " + ArrayUtils.toString(presolvedZlb.toArray()));
            log.debug("presolvedZub: " + ArrayUtils.toString(presolvedZub.toArray()));
        }

        if (n == 0) {
            // deterministic problem
            double[] sol = lpPresolver.postsolve(new double[] {});
            assertEquals(expectedSolution.length, sol.length);
            for (int i = 0; i < sol.length; i++) {
                // log.debug("i: " + i);
                assertEquals(expectedSolution[i], sol[i], 1.e-9);
            }
        } else {

            Utils.writeDoubleArrayToFile(presolvedC.toArray(),
                    "target" + File.separator + "presolvedC_" + problemName + ".txt");
            Utils.writeDoubleMatrixToFile(presolvedA.toArray(),
                    "target" + File.separator + "presolvedA_" + problemName + ".csv");
            Utils.writeDoubleArrayToFile(presolvedB.toArray(),
                    "target" + File.separator + "presolvedB_" + problemName + ".txt");
            Utils.writeDoubleArrayToFile(presolvedLb.toArray(),
                    "target" + File.separator + "presolvedLB_" + problemName + ".txt");
            Utils.writeDoubleArrayToFile(presolvedUb.toArray(),
                    "target" + File.separator + "presolvedUB_" + problemName + ".txt");

            // check objective function
            double delta = expectedTolerance;
            RealVector presolvedES = MatrixUtils.createRealVector(lpPresolver.presolve(expectedSolution));
            double presolvedEV = MatrixUtils.createRealVector(presolvedC.toArray()).dotProduct(presolvedES);// in general it is different from the optimal value
            log.debug("presolved expected value: " + presolvedEV);
            RealVector postsolvedES = MatrixUtils.createRealVector(lpPresolver.postsolve(presolvedES.toArray()));
            double postsolvedEV = MatrixUtils.createRealVector(c).dotProduct(postsolvedES);
            //assertEquals(expectedValue, postsolvedEV, delta);
            assertTrue(Math.abs((expectedValue - postsolvedEV) / expectedValue) < delta);

            // check postsolved constraints
            for (int i = 0; i < lb.length; i++) {
                double di = Double.isNaN(lb[i]) ? -Double.MAX_VALUE : lb[i];
                assertTrue(di <= postsolvedES.getEntry(i) + delta);
            }
            for (int i = 0; i < ub.length; i++) {
                double di = Double.isNaN(ub[i]) ? Double.MAX_VALUE : ub[i];
                assertTrue(di + delta >= postsolvedES.getEntry(i));
            }
            RealVector Axmb = AMatrix.operate(postsolvedES).subtract(bVector);
            assertEquals(0., Axmb.getNorm(), 1.5 * expectedTolerance);

            // check presolved constraints
            assertEquals(presolvedLb.size(), presolvedES.getDimension());
            assertEquals(presolvedUb.size(), presolvedES.getDimension());
            AMatrix = MatrixUtils.createRealMatrix(presolvedA.toArray());//reassigned to avoid memory consumption
            bVector = MatrixUtils.createRealVector(presolvedB.toArray());
            for (int i = 0; i < presolvedLb.size(); i++) {
                double di = Double.isNaN(presolvedLb.getQuick(i)) ? -Double.MAX_VALUE : presolvedLb.getQuick(i);
                assertTrue(di <= presolvedES.getEntry(i) + delta);
            }
            for (int i = 0; i < presolvedUb.size(); i++) {
                double di = Double.isNaN(presolvedUb.getQuick(i)) ? Double.MAX_VALUE : presolvedUb.getQuick(i);
                assertTrue(di + delta >= presolvedES.getEntry(i));
            }
            Axmb = AMatrix.operate(presolvedES).subtract(bVector);
            assertEquals(0., Axmb.getNorm(), 1.5 * expectedTolerance);

            //check for 0-rows
            List<Integer> zeroRows = new ArrayList<Integer>();
            for (int i = 0; i < presolvedA.rows(); i++) {
                boolean isNotZero = false;
                for (int j = 0; !isNotZero && j < presolvedA.columns(); j++) {
                    isNotZero = Double.compare(0., presolvedA.getQuick(i, j)) != 0;
                }
                if (!isNotZero) {
                    zeroRows.add(zeroRows.size(), i);
                }
            }
            if (!zeroRows.isEmpty()) {
                log.debug("All 0 entries in rows " + ArrayUtils.toString(zeroRows));
                fail();
            }

            //check for 0-columns
            List<Integer> zeroCols = new ArrayList<Integer>();
            for (int j = 0; j < presolvedA.columns(); j++) {
                boolean isNotZero = false;
                for (int i = 0; !isNotZero && i < presolvedA.rows(); i++) {
                    isNotZero = Double.compare(0., presolvedA.getQuick(i, j)) != 0;
                }
                if (!isNotZero) {
                    zeroCols.add(zeroCols.size(), j);
                }
            }
            if (!zeroCols.isEmpty()) {
                log.debug("All 0 entries in columns " + ArrayUtils.toString(zeroCols));
                fail();
            }

            // check rank(A): must be A pXn with rank(A)=p < n
            qr = new QRSparseFactorization(new SparseDoubleMatrix2D(presolvedA.toArray()));
            qr.factorize();
            boolean isFullRank = qr.hasFullRank();
            log.debug("p        : " + AMatrix.getRowDimension());
            log.debug("n        : " + AMatrix.getColumnDimension());
            log.debug("full rank: " + isFullRank);
            assertTrue(AMatrix.getRowDimension() < AMatrix.getColumnDimension());
            assertTrue(isFullRank);
        }
    }
}