FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Polygon - Defining nonlinear constraints

Description
Maximize the area of polygon of N vertices and diameter of 1. This example demonstrates how to build nonlinear formulae from strings and token sequences.

polygon_java.zip[download all files]

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
PolygonObjects.java[download]





PolygonObjects.java

// (c) 2023-2024 Fair Isaac Corporation

import static com.dashoptimization.objects.Utils.cos;
import static com.dashoptimization.objects.Utils.sin;
import static com.dashoptimization.objects.Utils.sum;

import com.dashoptimization.ColumnType;
import com.dashoptimization.DefaultMessageListener;
import com.dashoptimization.XPRSconstants;
import com.dashoptimization.XPRSenumerations;
import com.dashoptimization.objects.Expression;
import com.dashoptimization.objects.Variable;
import com.dashoptimization.objects.XpressProblem;

/**
 * Maximize the area of a polygon of N vertices and a diameter of 1. The
 * position of vertices is indicated as (r,theta) coordinates where r denotes
 * the distance to the base point (vertex with number N) and theta the angle
 * from the x-axis.
 */
public class PolygonObjects {

    // the number of vertices/sides of the polygon
    private static final int NSIDES = 5;

    public static void main(String[] args) {
        try (XpressProblem prob = new XpressProblem()) {
            // Output all messages.
            prob.callbacks.addMessageCallback(DefaultMessageListener::console);

            /**** VARIABLES ****/

            // r corresponds to the distance from the base point to vertex i
            Variable[] r = prob.addVariables(NSIDES - 1).withName(i -> String.format("r_%d", i)).withUB(1.0).toArray();

            // theta corresponds to the angle relative to the x-axis of vertex i
            Variable[] theta = prob.addVariables(NSIDES - 1).withName(i -> String.format("theta_%d", i)).withUB(Math.PI)
                    .toArray();

            // objective transfer column
            Variable objtransfercol = prob.addVariable(XPRSconstants.MINUSINFINITY, XPRSconstants.PLUSINFINITY,
                    ColumnType.Continuous, "objTransferCol");

            /**** OBJECTIVE ****/

            // Set objective: maximize area of the polygon: r_i*r_j*sin(theta_i+1-theta_i)/2
            Expression area = sum(NSIDES - 2, i -> r[i].mul(r[i + 1]).mul(sin(theta[i + 1].minus(theta[i]))).div(2));

            // To make the objective linear, just maximize the objtransfercol
            prob.setObjective(objtransfercol, XPRSenumerations.ObjSense.MAXIMIZE);

            // Add the objective transfer row: area = objtransfercol
            prob.addConstraint(area.eq(objtransfercol));

            /**** CONSTRAINTS ****/

            // any two non-origin nodes should have a distance <= 1 to satisfy the diameter
            for (int i = 0; i < NSIDES - 1; i++) {
                for (int j = i + 1; j < NSIDES - 1; j++) {
                    // r_i^2 + r_j^2 - 2 * r_i * r_j * cos(theta_j - theta_i) <= 1
                    prob.addConstraint(r[i].square().plus(r[j].square())
                            .minus(r[i].mul(r[j]).mul(cos(theta[j].minus(theta[i])))).leq(1.0));
                }
            }

            // Ordering of the vertices: theta_i+1 >= theta_i
            prob.addConstraints(NSIDES - 2, i -> theta[i + 1].geq(theta[i]));

            // Dump the problem to disk so that we can inspect it.
            prob.writeProb("polygon.lp", "lp");

            // Solve to local optimality
            prob.controls().setNLPSolver(XPRSconstants.NLPSOLVER_LOCAL);

            // Solve
            prob.optimize();
            if (prob.attributes().getSolStatus() != XPRSenumerations.SolStatus.OPTIMAL
                    && prob.attributes().getSolStatus() != XPRSenumerations.SolStatus.FEASIBLE)
                throw new RuntimeException("optimization failed with status " + prob.attributes().getSolStatus());
            double[] sol = prob.getSolution();
            // Printing the objective is currently not supported for nonlinear
            // System.out.println("Objective: " + prob.attributes().getNLPObjVal());
            // Print out the solution
            for (Variable var : r) {
                System.out.print(var.getName() + ":" + var.getValue(sol) + " ");
            }
            System.out.println();
            for (Variable var : theta) {
                System.out.print(var.getName() + ":" + var.getValue(sol) + " ");
            }
            System.out.println();
        }
    }
}

Back to examples browserPrevious exampleNext example