| BoolVars.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using System;
using System.Linq;
using System.Collections.Generic;
using Optimizer.Maps;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using static Optimizer.Objects.LinExpression;
using static Optimizer.Objects.ConstantExpression;
using Optimizer;
namespace XpressExamples
{
    /// <summary>
    /// Stating logic clauses that resemble SAT-type formulations
    /// </summary>
    public class BoolVars
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Formulating the bool vars example problem");
            const int R = 5;
            using (XpressProblem prob = new XpressProblem())
            {
                // create boolean variables and their negations
                Variable[] x = prob.AddVariables(R)
                  .WithType(ColumnType.Binary)
                  .WithName("x_{0}")
                  .WithUB(1)
                  .ToArray();
                Variable[] x_neg = prob.AddVariables(R)
                  .WithType(ColumnType.Binary)
                  .WithName("x_neg_{0}")
                  .WithUB(1)
                  .ToArray();
                // add 2 helper variables for stating logical constraints
                Variable trueVar = prob.AddVariable(0, 1, ColumnType.Binary, "TRUE");
                Variable falseVar = prob.AddVariable(0, 1, ColumnType.Binary, "FALSE");
                // fix these helper variables to TRUE and FALSE, respectively.
                prob.AddConstraint(trueVar == 1);
                prob.AddConstraint(falseVar == 0);
                // add the complement relation between each binary variable and its negation.
                prob.AddConstraints(R,
                    r => (1 * x[r] + 1 * x_neg[r] == 1));
                // add a direct equation constraint between certain variables.
                prob.AddConstraint(x[2] == x_neg[3]);
                // express some clauses on the variables
                // require that  x(0) and x_neg(4) = true
                // we use trueVar as the resultant of a logical "and" constraint
                prob.AddConstraint(trueVar.AndOf(new Variable[] { x[0], x_neg[4] }));
                // ! 'x(0) or x(2)' must be true
                prob.AddConstraint(trueVar.OrOf(new Variable[] { x[0], x[2] }));
                //  for more complicated expressions, we need auxiliary variables.
                Variable andResultant1 = prob.AddVariable(0, 1, ColumnType.Binary, "andresultant1");
                Variable andResultant2 = prob.AddVariable(0, 1, ColumnType.Binary, "andresultant2");
                // both constraints below could be formulated using andResultant[12].AndOf(...)
                // here, however, we highlight the connection to general constraints
                // the first AND is between x[0] .. x[2]
                prob.AddConstraint(andResultant1.AndOf(x.Take(3).ToArray()));
                //  the second AND is between x_neg[3] and x_neg[4]
                prob.AddConstraint(andResultant2.AndOf(x_neg.Skip(3).ToArray()));
                // add those two individual AND resultants by requiring at least one to be satisfied
                prob.AddConstraint(trueVar.OrOf(new Variable[] { andResultant1, andResultant2 }));
                // finally, add a constraint that none of x_neg[0 .. 2] should be true
                prob.AddConstraint(falseVar.OrOf(x_neg.Take(3).ToArray()));
                // set constant objective function with a maximization sense
                prob.SetObjective(Constant(0), Optimizer.ObjSense.Maximize);
                // write the problem in LP format for manual inspection
                Console.WriteLine("Writing the problem to 'BoolVars.lp'");
                prob.WriteProb("BoolVars.lp", "l");
                // Solve the problem
                Console.WriteLine("Solving the problem");
                prob.Optimize();
                // check the solution status
                Console.WriteLine("Problem finished with SolStatus {0}", prob.SolStatus);
                if (prob.SolStatus != Optimizer.SolStatus.Optimal)
                {
                    throw new Exception("Problem not solved to optimality");
                }
                // print the optimal solution of the problem to the console
                Console.WriteLine("Solution has objective value (profit) of {0}", prob.ObjVal);
                Console.WriteLine("");
                Console.WriteLine("*** Solution ***");
                double[] sol = prob.GetSolution();
                for (int r = 0; r < R; r++)
                {
                    string delim = r < R - 1 ? ", " : "\n";
                    Console.Write($"x_{r} = {x[r].GetValue(sol)}{delim}");
                }
                for (int r = 0; r < R; r++)
                {
                    string delim = r < R - 1 ? ", " : "\n";
                    Console.Write($"x_neg_{r} = {x_neg[r].GetValue(sol)}{delim}");
                }
                Console.WriteLine("");
            }
        }
    }
}
 | 
| 
 | 
| BoolVars.csproj | 
| <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <XpressExampleFiles Condition="'$(XpressExampleFiles)'==''">../../../data</XpressExampleFiles>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="FICO.Xpress.XPRSdn" Version="41.1.1" /> <!-- Version 41.1.1 or later -->
  </ItemGroup>
</Project>
 | 
| 
 | 
| GeneralConstraints.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using System;
using System.Linq;
using System.Collections.Generic;
using Optimizer.Maps;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using static Optimizer.Objects.LinExpression;
using static Optimizer.XPRSprob;
using static Optimizer.Objects.ConstantExpression;
using Optimizer;
namespace XpressExamples
{
    /// <summary>
    /// A simple example that formulates some constraints on the minimum and absolute values
    /// of linear combinations of variables.
    /// </summary>
    public class GeneralConstraints
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Formulating the general constraint example problem");
            const int R = 3;
            using (XpressProblem prob = new XpressProblem())
            {
                Variable[] x = prob.AddVariables(R)
                  .WithName("x_{0}")
                  .WithUB(20)
                  .ToArray();
                Variable y = prob.AddVariable("y");
                Variable z = prob.AddVariable("z");
                Expression objective = Sum(x);
                // We want to formulate abs(x(0)-2*x(1)) <= 10. We need to introduce
                // two auxiliary variables for the argument of the abs function
                //  and then break down the abs expression in multiple steps
                Variable diff1 = prob.AddVariable("diff1");
                Variable absOfDiff1 = prob.AddVariable("absOfDiff1");
                prob.AddConstraint(diff1 == x[0] - 2 * x[1]);
                prob.AddConstraint(absOfDiff1.AbsOf(diff1));
                prob.AddConstraint(absOfDiff1 <= 10);
                // We link a new variable to the minimum of the x(i) and
                // require this variable to be >= 5
                // Clearly, this bound constraint could also be achieved by simply setting
                // the bounds of each x variable.
                Variable minOfX = prob.AddVariable("minOfX");
                prob.AddConstraint(minOfX.MinOf(x));
                prob.AddConstraint(minOfX >= 5);
                // We link variable y to the maximum of other variables, expressions, and constants
                // y = max(x(2), 20, x(0)-z)
                Variable diff2 = prob.AddVariable("diff2");
                prob.AddConstraint(diff2 == x[0] - 1 * z);
                // the below code is equivalent to using the MaxOf function on the resultant y
                // prob.AddConstraint(y.MaxOf(new Variable[] {x[2], diff2}, 20).SetName("max_constraint"));
                prob.AddConstraint(y.MaxOf(new Variable[] { x[2], diff2 }, new double[] { 20 }, "max_constraint"));
                // set objective function with a maximization sense
                prob.SetObjective(objective, Optimizer.ObjSense.Maximize);
                // write the problem in LP format for manual inspection
                Console.WriteLine("Writing the problem to 'GeneralConstraints.lp'");
                prob.WriteProb("GeneralConstraints.lp", "l");
                // Solve the problem
                Console.WriteLine("Solving the problem");
                prob.Optimize();
                // check the solution status
                Console.WriteLine("Problem finished with SolStatus {0}", prob.SolStatus);
                if (prob.SolStatus != Optimizer.SolStatus.Optimal)
                {
                    throw new Exception("Problem not solved to optimality");
                }
                // print the optimal solution of the problem to the console
                Console.WriteLine("Solution has objective value (profit) of {0}", prob.ObjVal);
                Console.WriteLine("");
                Console.WriteLine("*** Solution ***");
                double[] sol = prob.GetSolution();
                for (int r = 0; r < R; r++)
                {
                    string delim = r < R - 1 ? ", " : "\n";
                    Console.Write($"x_{r} = {x[r].GetValue(sol)}{delim}");
                }
                Console.WriteLine($"y = {y.GetValue(sol)}, z = {z.GetValue(sol)}");
                Console.WriteLine($"ABS ( x[0] - 2*x[1] ) = {absOfDiff1.GetValue(sol)}, minOfX = {minOfX.GetValue(sol)}");
                Console.WriteLine("");
            }
        }
    }
}
 | 
| 
 | 
| GeneralConstraints.csproj | 
| <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <XpressExampleFiles Condition="'$(XpressExampleFiles)'==''">../../../data</XpressExampleFiles>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="FICO.Xpress.XPRSdn" Version="41.1.1" /> <!-- Version 41.1.1 or later -->
  </ItemGroup>
</Project>
 | 
| 
 | 
| PiecewiseLinear.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using System;
using System.Linq;
using System.Collections.Generic;
using Optimizer.Maps;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using static Optimizer.Objects.LinExpression;
using static Optimizer.XPRSprob;
using static Optimizer.Objects.ConstantExpression;
using Optimizer;
namespace XpressExamples
{
    /// <summary>
    /// An example that demonstrates how to model a piecewise linear cost function.
    /// A piecewise linear cost function f(x) assigns a different linear cost function
    /// for different intervals of the domain of its argument x.
    /// This situation occurs in real-world problems if
    /// there are price discounts available starting from a certain quantity of sold goods.
    ///
    /// - Example discussed in mipformref whitepaper -
    /// </summary>
    public class PiecewiseLinear
    {
        public static void Main(string[] args)
        {
            const int NB = 6;
            // define breakpoints as (x,y)-coordinates. Note that
            // some breakpoints share the same x-coordinate, but have
            // different values for y.
            // The optimizer handles this case correctly.
            // In practice, such noncontinuous piecewise linear functions
            // can model price discounts for example.
            PwlBreakpoint[] breakpoints = new PwlBreakpoint[NB] {
              new PwlBreakpoint(  0,   0),
              new PwlBreakpoint( 50,  50),
              new PwlBreakpoint( 50,  75),
              new PwlBreakpoint(120, 180),
              new PwlBreakpoint(120, 240),
              new PwlBreakpoint(200, 400)
            };
            Console.WriteLine("Formulating the piecewise linear example problem");
            using (XpressProblem prob = new XpressProblem())
            {
                Variable x = prob.AddVariable("x");
                Variable fx = prob.AddVariable("fx");
                Expression objective = fx;
                prob.AddConstraint(fx.PwlOf(x, breakpoints, "pwl_with_breakpoints"));
                // ! Add a lower bound on x to get a somewhat more meaningful model
                // x >= 150
                x.SetLB(150);
                // set objective function with a minimization sense
                prob.SetObjective(objective, Optimizer.ObjSense.Minimize);
                // write the problem in LP format for manual inspection
                Console.WriteLine("Writing the problem to 'PiecewiseLinear.lp'");
                prob.WriteProb("PiecewiseLinear.lp", "l");
                // Solve the problem
                Console.WriteLine("Solving the problem");
                prob.Optimize();
                // check the solution status
                Console.WriteLine("Problem finished with SolStatus {0}", prob.SolStatus);
                if (prob.SolStatus != Optimizer.SolStatus.Optimal)
                {
                    throw new Exception("Problem not solved to optimality");
                }
                // print the optimal solution of the problem to the console
                Console.WriteLine("Solution has objective value (profit) of {0}", prob.ObjVal);
                Console.WriteLine("");
                Console.WriteLine("*** Solution ***");
                double[] sol = prob.GetSolution();
                Console.WriteLine($"x = {x.GetValue(sol)}, fx = {fx.GetValue(sol)}");
                Console.WriteLine("");
            }
        }
    }
}
 | 
| 
 | 
| PiecewiseLinear.csproj | 
| <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <XpressExampleFiles Condition="'$(XpressExampleFiles)'==''">../../../data</XpressExampleFiles>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="FICO.Xpress.XPRSdn" Version="41.1.1" /> <!-- Version 41.1.1 or later -->
  </ItemGroup>
</Project>
 | 
| 
 | 
| QuadraticProgramming.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using Optimizer;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using System;
namespace XpressExamples
{
    /// <summary>Small Quadratic Programming example.</summary>
    /// <remarks>
    /// <code>
    ///    minimize x1 + x1^2 +2x1x2 +2x2^2 +x4^2
    ///    s.t.
    ///      C1:  x1 +2x2 -4x4 >= 0
    ///      C2: 3x1 -2x3 - x4 <= 100
    ///      C3: 10 <= x1 +3x2 +3x3 -2x4 <= 30
    ///      0 <= x1 <= 20
    ///      0 <= x2,x3
    ///      x4 free
    /// </code>
    /// </remarks>
    public class QuadraticProgramming
    {
        static readonly int N = 4;
        public static void Main(string[] args)
        {
            using (XpressProblem prob = new XpressProblem())
            {
                prob.callbacks.AddMessageCallback(DefaultMessageListener.Console);
                ///// VARIABLES
                Variable[] x = new Variable[N];
                x[0] = prob.AddVariable(0, 20, ColumnType.Continuous, "x1");
                x[1] = prob.AddVariable("x2");
                x[2] = prob.AddVariable("x3");
                x[3] = prob.AddVariable(Double.NegativeInfinity, Double.PositiveInfinity, ColumnType.Continuous, "x4");
                ///// OBJECTIVE
                QuadExpression obj = QuadExpression.Create();
                obj.AddTerm(x[0]);
                obj.AddTerm(x[0], x[0]);
                obj.AddTerm(2 * x[0] * x[1]);
                obj.AddTerm(2 * x[1] * x[1]);
                obj.AddTerm(x[3].Square());
                prob.SetObjective(obj, ObjSense.Minimize);
                ///// CONSTRAINTS
                prob.AddConstraint((x[0] + 2 * x[1] - 4 * x[3] >= 0).SetName("C1"));
                prob.AddConstraint((3 * x[0] - 2 * x[2] - x[3] <= 100).SetName("C2"));
                prob.AddConstraint((x[0] + 3 * x[1] + 3 * x[2] - 2 * x[3]).In(10, 30).SetName("C3"));
                ///// SOLVING + OUTPUT
                prob.WriteProb("qp.lp");
                prob.LpOptimize();
                Console.WriteLine("Problem status: " + prob.MIPStatus);
                if (prob.LPStatus != LPStatus.Optimal)
                    throw new Exception("optimization failed with status " + prob.LPStatus);
                Console.WriteLine("Objective function value: " + prob.ObjVal);
                double[] sol = prob.GetSolution();
                for (int i = 0; i < N; i++)
                    Console.Write(x[i].GetName() + ": " + x[i].GetValue(sol) + ", ");
                Console.WriteLine();
            }
        }
    }
}
 | 
| 
 | 
| QuadraticProgramming.csproj | 
| <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <XpressExampleFiles Condition="'$(XpressExampleFiles)'==''">../../../data</XpressExampleFiles>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="FICO.Xpress.XPRSdn" Version="41.1.1" /> <!-- Version 41.1.1 or later -->
  </ItemGroup>
  
</Project>
 | 
| 
 | 
| SpecialOrderedSets.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using System;
using System.Linq;
using System.Collections.Generic;
using Optimizer.Maps;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using static Optimizer.XPRSprob;
using static Optimizer.Objects.SOS;
using Optimizer;
namespace XpressExamples
{
    /// <summary>
    /// Approximation of a nonlinear function by a special ordered set (SOS-2).
    /// </summary>
    /// <remarks>
    /// An SOS-2 is a constraint that allows at most 2 of its variables to
    /// have a nonzero value. In addition, these variables have to be adjacent.
    ///
    /// Example discussed in mipformref whitepaper
    /// </remarks>
    public class SpecialOrderedSets
    {
        public static void Main(string[] args)
        {
            const int NB = 4; // number of breakpoints
            double[] B_X = // X coordinates of breakpoints
                new double[NB] { 1, 2.5, 4.5, 6.5 };
            double[] B_Y = // Y coordinates of breakpoints
                new double[NB] { 1.5, 6, 3.5, 2.5 };
            Console.WriteLine("Formulating the special ordered sets example problem");
            using (XpressProblem prob = new XpressProblem())
            {
                // create one w variable for each breakpoint. We express
                Variable[] w = prob.AddVariables(NB)
                  .WithName("w_{0}")
                  .WithUB(1)
                  .ToArray();
                Variable x = prob.AddVariable("x");
                Variable y = prob.AddVariable("y");
                // Define the SOS-2 with weights from B_X. This is necessary to
                // establish the ordering between the w variables.
                prob.AddConstraint(SOS.Sos2(w, B_X, "SOS_2"));
                // We use the w variables to express a convex combination.
                // In combination with the above SOS-2 condition,
                // X and Y are represented as a convex combination of 2 adjacent
                // breakpoints.
                prob.AddConstraint(Sum(w) == 1);
                // The below constraints express the actual locations of X and Y
                // in the plane as a convex combination of the breakpoints, subject
                // to the assignment found for the w variables.
                prob.AddConstraint(x == ScalarProduct(w, B_X));
                prob.AddConstraint(y == ScalarProduct(w, B_Y));
                // set lower and upper bounds on x
                x.SetLB(2); x.SetUB(6);
                // set objective function with a maximization sense
                prob.SetObjective(y, Optimizer.ObjSense.Minimize);
                // write the problem in LP format for manual inspection
                Console.WriteLine("Writing the problem to 'SpecialOrderedSets.lp'");
                prob.WriteProb("SpecialOrderedSets.lp", "l");
                // Solve the problem
                Console.WriteLine("Solving the problem");
                prob.Optimize();
                // check the solution status
                Console.WriteLine("Problem finished with SolStatus {0}", prob.SolStatus);
                if (prob.SolStatus != Optimizer.SolStatus.Optimal)
                {
                    throw new Exception("Problem not solved to optimality");
                }
                // print the optimal solution of the problem to the console
                Console.WriteLine("Solution has objective value (profit) of {0}\n", prob.ObjVal);
                Console.WriteLine("*** Solution ***");
                double[] sol = prob.GetSolution();
                for (int b = 0; b < NB; b++)
                {
                    string delim = b < NB - 1 ? ", " : "\n";
                    Console.Write($"w_{b} = {w[b].GetValue(sol)}{delim}");
                }
                Console.WriteLine($"x = {x.GetValue(sol)}, y = {y.GetValue(sol)}");
            }
        }
    }
}
 | 
| 
 | 
| SpecialOrderedSets.csproj | 
| <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <XpressExampleFiles Condition="'$(XpressExampleFiles)'==''">../../../data</XpressExampleFiles>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="FICO.Xpress.XPRSdn" Version="41.1.1" /> <!-- Version 41.1.1 or later -->
  </ItemGroup>
</Project>
 | 
| 
 | 
| SpecialOrderedSetsQuadratic.cs | 
| // (c) 2023-2024 Fair Isaac Corporation
using System;
using System.Linq;
using System.Collections.Generic;
using Optimizer.Maps;
using Optimizer.Objects;
using static Optimizer.Objects.Utils;
using static Optimizer.XPRSprob;
using static Optimizer.Objects.ConstantExpression;
using static Optimizer.Objects.SOS;
using Optimizer;
namespace XpressExamples
{
    /// <summary>
    /// Approximation of a quadratic function in 2 variables by special ordered sets (SOS-2).
    /// </summary>
    /// <remarks>
    /// An SOS-2 is a constraint that allows at most 2 of its variables to
    /// have a nonzero value. In addition, these variables have to be adjacent.
    ///
    /// Example discussed in mipformref whitepaper.
    /// </remarks>
    public class SpecialOrderedSetsQuadratic
    {
        public static void Main(string[] args)
        {
            const int NX = 10; // number of breakpoints on the X-axis
            const int NY = 10; // number of breakpoints on the Y-axis
            double[] X = // X coordinates of grid points
                new double[NX];
            double[] Y = // Y coordinates of breakpoints
                new double[NY];
            double[,] F_XY = // two dimensional array of function values on the grid points
                new double[NX, NY];
            // assign the toy data
            for (int i = 0; i < NX; i++) X[i] = i + 1;
            for (int i = 0; i < NY; i++) Y[i] = i + 1;
            for (int i = 0; i < NX; i++) for (int j = 0; j < NY; j++) F_XY[i, j] = (X[i] - 5) * (Y[j] - 5);
            Console.WriteLine("Formulating the special ordered sets quadratic example problem");
            using (XpressProblem prob = new XpressProblem())
            {
                // create one w variable for each X breakpoint. We express
                Variable[] wx = prob.AddVariables(NX)
                  .WithName("wx_{0}")
                  .WithUB(1)  // this upper bound i redundant because of the convex combination constraint on the sum of the wx
                  .ToArray();
                // create one w variable for each Y breakpoint. We express
                Variable[] wy = prob.AddVariables(NY)
                  .WithName("wy_{0}")
                  .WithUB(1)  // this upper bound i redundant because of the convex combination constraint on the sum of the wy
                  .ToArray();
                // create a two-dimensional array of w variable for each grid point. We express
                Variable[,] wxy = prob.AddVariables(NX, NY)
                  .WithName("wxy_{0}_{1}")
                  .WithUB(1)  // this upper bound i redundant because of the convex combination constraint on the sum of the wy
                  .ToArray();
                Variable x = prob.AddVariable("x");
                Variable y = prob.AddVariable("y");
                Variable fxy = prob.AddVariable("fxy");
                // make fxy a free variable
                fxy.SetLB(double.NegativeInfinity);
                // Define the SOS-2 constraints with weights from X and Y. This
                // is necessary to establish the ordering between variables in wx
                // and in wy.
                prob.AddConstraint(SOS.Sos2(wx, X, "SOS_2_X"));
                prob.AddConstraint(SOS.Sos2(wy, Y, "SOS_2_Y"));
                prob.AddConstraint(Sum(wx) == 1);
                prob.AddConstraint(Sum(wy) == 1);
                // link the wxy variables to their 1-dimensional colleagues
                prob.AddConstraints(NX,
                  i => (wx[i] == Sum(NY, j => wxy[i, j]))
                );
                prob.AddConstraints(NY,
                  j => (wy[j] == Sum(NX, i => wxy[i, j]))
                );
                // now express the actual x, y, and f(x,y) coordinates
                prob.AddConstraint(x == ScalarProduct(wx, X));
                prob.AddConstraint(y == ScalarProduct(wy, Y));
                prob.AddConstraint(fxy == Sum(NX, i => Sum(NY, j => wxy[i, j] * F_XY[i, j])));
                // set lower and upper bounds on x and y
                x.SetLB(2); x.SetUB(10);
                y.SetLB(2); y.SetUB(10);
                // set objective function with a minimization sense
                prob.SetObjective(fxy, Optimizer.ObjSense.Minimize);
                // write the problem in LP format for manual inspection
                Console.WriteLine("Writing the problem to 'SpecialOrderedSetsQuadratic.lp'");
                prob.WriteProb("SpecialOrderedSetsQuadratic.lp", "l");
                // Solve the problem
                Console.WriteLine("Solving the problem");
                prob.Optimize();
                // check the solution status
                Console.WriteLine("Problem finished with SolStatus {0}", prob.SolStatus);
                if (prob.SolStatus != Optimizer.SolStatus.Optimal)
                {
                    throw new Exception("Problem not solved to optimality");
                }
                // print the optimal solution of the problem to the console
                Console.WriteLine("Solution has objective value (profit) of {0}\n", prob.ObjVal);
                Console.WriteLine("*** Solution ***");
                double[] sol = prob.GetSolution();
                for (int i = 0; i < NX; i++)
                {
                    string delim = i < NX - 1 ? ", " : "\n";
                    Console.Write($"wx_{i} = {wx[i].GetValue(sol)}{delim}");
                }
                for (int j = 0; j < NY; j++)
                {
                    string delim = j < NY - 1 ? ", " : "\n";
                    Console.Write($"wy_{j} = {wy[j].GetValue(sol)}{delim}");
                }
                Console.WriteLine($"x = {x.GetValue(sol)}, y = {y.GetValue(sol)}");
            }
        }
    }
}
 | 
| 
 |