////
//  Copyright: Copyright (c) MOSEK ApS, Denmark. All rights reserved.
//
//  File:      facility_location.cs
//
//  Purpose: Demonstrates a small one-facility location problem.
//
//  Given 10 customers placed in a grid we wish to place a facility
//  somewhere so that the total sum of distances to customers is
//  minimized.
//
//  The problem is formulated as a conic optimization problem as follows.
//  Let f=(fx,fy) be the (unknown) location of the facility, and let
//  c_i=(cx_i,cy_i) be the (known) customer locations; then we wish to
//  minimize
//      sum_i || f - c_i ||
//  where
//      ||.||
//  denotes the euclidian norm.
//  This is formulated as
//
//  minimize   sum(d_i)
//  such that  d_i ^ 2 > tx_i ^ 2 + ty_i ^ 2, for all i
//             tx_i = cx_i - fx, for all i
//             ty_i = cy_i - fy, for all i
//             d_i > 0, for all i
////

using System;
using mosek.fusion;

namespace mosek.fusion.example
{
  public class facility_location
  {
    // Customer locations
    private static Matrix  customerloc =
      Matrix.Dense (new double[,]
    { { 12,  2 },
      { 15, 13 },
      { 10,  8 },
      {  0, 10 },
      {  6, 13 },
      {  5,  8 },
      { 10, 12 },
      {  4,  6 },
      {  5,  2 },
      {  1, 10 }
    } );
    private static int N = customerloc.NumRows();
    public static void Main(string[] args)
    {
      using (Model M = new Model("FacilityLocation"))
      {
        // Variable holding the facility location
        Variable f = M.Variable("facility", Set.Make(1, 2), Domain.Unbounded());
        // Variable defining the euclidian distances to each customer
        Variable d = M.Variable("dist", Set.Make(N, 1), Domain.GreaterThan(0.0));
        // Variable defining the x and y differences to each customer;
        Variable t = M.Variable("t", Set.Make(N, 2), Domain.Unbounded());
        M.Constraint("dist measure",
        Var.Hstack(new Variable[] { d, t }),
        Domain.InQCone(N, 3));

        Variable fxy = Var.Repeat(f, N);
        M.Constraint("xy diff", Expr.Add(t, fxy), Domain.EqualsTo(customerloc));

        M.Objective("total_dist", ObjectiveSense.Minimize, Expr.Sum(d));

        M.Solve();
        M.WriteTask("facility_location.task");
        double[] floc = f.Level();
        Console.WriteLine("Facility location = {0},{1}", floc[0], floc[1]);
      }
    }
  }
}
