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

Catenary - Solving a QCQP

Description
This model finds the shape of a hanging chain by minimizing its potential energy.

catenary_dnet.zip[download all files]

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





Catenary.cs

// (c) 2023-2024 Fair Isaac Corporation

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

namespace XpressExamples
{
    /// <summary>QCQP problem (linear objective, convex quadratic constraints)</summary>
    /// <remarks>
    ///   Based on AMPL model catenary.mod
    ///  (Source: http://www.orfe.princeton.edu/~rvdb/ampl/nlmodels/)
    ///
    ///   This model finds the shape of a hanging chain by minimizing
    ///   its potential energy.
    /// </remarks>
    class Catenary
    {
        static readonly int N = 100;              /// Number of chainlinks
        static readonly int L = 1;                /// Difference in x-coordinates of endlinks

        static readonly double H = 2.0 * L / N;   /// Length of each link

        public static void Main(string[] args)
        {
            using (XpressProblem prob = new XpressProblem())
            {
                // Variables: x-coordinates
                Variable[] x = prob.AddVariables(N + 1)
                    .WithName("x({0})")
                    .WithLB(XPRS.MINUSINFINITY)
                    .ToArray();

                // Variables: y-coordinates
                Variable[] y = prob.AddVariables(N + 1)
                    .WithName("y({0})")
                    .WithLB(XPRS.MINUSINFINITY)
                    .ToArray();

                // Bounds: positions of endpoints
                // Left anchor
                x[0].Fix(0);
                y[0].Fix(0);
                // Right anchor
                x[N].Fix(L);
                y[N].Fix(0);

                /// Objective: Minimise the potential energy
                /// sum(j in 1..N) (y(j-1)+y(j))/2
                LinExpression obj = LinExpression.Create();
                for (int i = 1; i <= N; i++)
                {
                    obj.AddTerm(0.5 * y[i - 1]).AddTerm(0.5 * y[i]);
                }
                prob.SetObjective(obj, ObjSense.Minimize);

                /// Constraint: positions of chainlinks
                /// forall(j in 1..N) (x(j)-x(j-1))^2+(y(j)-y(j-1))^2 <= H^2
                for (int i = 1; i <= N; i++)
                {
                    prob.AddConstraint(Sum(LinExpression.Create().AddTerm(x[i]).AddTerm(-x[i - 1]).Square(),
                                           LinExpression.Create().AddTerm(y[i]).AddTerm(-y[i - 1]).Square())
                                       .Leq(H * H).SetName($"Link_{i}"));
                }

                /// Solve the problem and write the solution
                prob.LpOptimize("");

                Console.WriteLine($"Solution: {prob.ObjVal}");
                for (int i = 0; i <= N; i++)
                {
                    Console.WriteLine($"{i}: {x[i].GetSolution()}, {y[i].GetSolution()}");
                }
            }
        }
    }
}

Back to examples browserPrevious exampleNext example