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

Contract - Semi-continuous variables

Description
A small MIP-problem example demonstrating how to define semi-continuous variables.

contract_dnet.zip[download all files]

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





ContractAllocation.cs

// (c) 2023-2024 Fair Isaac Corporation

using System;
using Optimizer;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;

namespace XpressExamples
{
    /// <summary>Contract allocation example.</summary>
    class ContractAllocation
    {
        static readonly int NDISTRICT = 6;   /* Number of districts */
        static readonly int NCONTRACT = 10;  /* Number of contracts */

        private static readonly double[] output = new double[]{ /* Max. output per district */
        50, 40, 10, 20, 70, 50
    };

        private static readonly double[] cost = new double[]{ /* Cost per district */
        50, 20, 25, 30, 45, 40
    };

        private static readonly double[] volume = new double[]{ /* Volume of contracts */
        20, 10, 30, 15, 20, 30, 10, 50, 10, 20
    };

        public static void Main(string[] args)
        {

            using (XpressProblem prob = new XpressProblem())
            {
                // Output all messages.
                prob.callbacks.AddMessageCallback(DefaultMessageListener.Console);

                /**** VARIABLES ****/
                /* Variables indicating whether a project is chosen */
                Variable[,] x = prob.AddVariables(NDISTRICT, NCONTRACT)
                    .WithType(ColumnType.Binary)
                    .WithName((d, c) => $"x_d{d + 1}_c{c + 1}")
                    .ToArray();
                /* Quantities allocated to contractors */
                Variable[,] y = prob.AddVariables(NDISTRICT, NCONTRACT)
                    .WithType(ColumnType.SemiContinuous)
                    .WithUB((d, c) => output[d])
                    .WithName((d, c) => $"q_d{d + 1}_c{c + 1}")
                    .WithLimit(5) // Set limit for the semi-continous variable
                    .ToArray();

                /**** CONSTRAINTS ****/
                // Cover the required volume
                //  for all c in [0,NCONTRACT[
                //    sum(d in [0,NDISTRICT[) y[d][c] >= volume[c]
                prob.AddConstraints(NCONTRACT,
                        c => Sum(NDISTRICT, d => y[d, c]).Geq(volume[c]).SetName($"Size_{c}")
                        );

                // "Min": at least 2 districts / contract
                //  for all c in [0,NCONTRACT[
                //    sum(d in [0,NDISTRICT[) x[d][c] >= 2
                prob.AddConstraints(NCONTRACT,
                        c => Sum(NDISTRICT, d => x[d, c]).Geq(2.0).SetName($"Min_{c}")
                        );

                // Do not exceed max. output
                //  for all d in [0,NDISTRICT[
                //    sum(c in [0,NCONTRACT[) y[d][c] <= output[d]
                prob.AddConstraints(NDISTRICT,
                        d => Sum(NCONTRACT, c => y[d, c]).Leq(output[d]).SetName($"Output_{d}")
                        );

                // If a contract is allocated to a district, then at least 1 unit is allocated to it
                //  for all d in [0,NDISTRICT[
                //    for all c in [0,NCONTRACT[
                //      x[d][c] <= y[d][c]
                prob.AddConstraints(NDISTRICT, NCONTRACT,
                        (d, c) => x[d, c].Leq(y[d, c]).SetName($"XY_{d}{c}")
                        );

                /****OBJECTIVE****/
                prob.SetObjective(
                    Sum(
                        NCONTRACT,
                        c => Sum(NDISTRICT, d => y[d, c] * cost[d])),
                    Optimizer.ObjSense.Minimize
                );

                // Output the matrix in LP format
                prob.WriteProb("Contract.lp", "l");
                // Solve
                prob.MipOptimize();
                if (prob.SolStatus != Optimizer.SolStatus.Optimal &&
                        prob.SolStatus != Optimizer.SolStatus.Feasible)
                    throw new Exception("optimization failed with status " + prob.SolStatus);
                // Print out the solution
                double[] sol = prob.GetSolution();
                Console.WriteLine("Objective: {0}", prob.MIPObjVal);
                foreach (Variable v in y)
                {
                    if (v.GetValue(sol) > 0.5)
                        Console.WriteLine($"{v.GetName()}:{v.GetValue(sol)} ");
                }
            }
        }
    }
}

Back to examples browserPrevious exampleNext example