Artelys Knitro Artelys Knitro Home
  • Documentation
  • logo-new-blancArtelys
Python / Knitro API Python / Pyomo Julia / JuMP

On this page

  • Introduction
  • Problem description
  • Modeling the separation constraint
  • Nonlinear model
  • Input data
  • Model implementation
  • Use cases
    • Circle air traffic
    • Sector of a circle
    • Two converging lines
    • Ten random aircraft
  • Model extensions
    • Objective only taking into account the changes in speed
    • Objective only taking into account the changes in heading angle
  • References

Aircraft Deconfliction

Adjust aircraft headings and speeds by the smallest amount that keeps every pair of trajectories conflict-free.

Notebook
Python / Knitro API Python / Pyomo Julia / JuMP

Introduction

We consider the problem of avoiding collisions between aircraft in the sky.

Given a set of aircraft with their current speed and straight direction at the current instant, the controller needs to give each aircraft a new heading and speed that ensure no collision will occur. This problem is known as conflict resolution or tactical deconfliction, as opposed to strategic deconfliction, which happens hours before flight, and collision avoidance, which addresses imminent conflicts.

The trajectories live in the Euclidean 2D plane, since we assume every aircraft flies at the same flight level. We also assume there is no conflict at the initial instant.

Here are the trajectories of eight aircraft, first flown on their nominal headings until they collide, then as the solver reroutes them:

Problem description

Input

  • A set of aircraft \(A\); for each aircraft \(i\in A\):
    • \(\overrightarrow{P_i^0} = (X_i, Y_i)\) the initial position of aircraft \(i\)
    • \(\overrightarrow{V_i} = (V_i\cos \Theta _i, V_i\sin \Theta _i)\) the nominal vector of velocity of aircraft \(i\), where \(V_i\) is the magnitude of nominal speed of aircraft \(i\), in NM/min, and \(\Theta _i\) is the nominal heading angle of aircraft \(i\), in radians
    • \(0\le Q_i^{\text{min}}\le Q_i^{\text{max}}\) the minimum and maximum scale factors applied to nominal speed of aircraft \(i\)
    • \(\Omega _i^{\text{min}}\le \Omega _i^{\text{max}}\), \(\left[\Omega _i^{\text{min}},~\Omega _i^{\text{max}}\right] \subset \left[-\dfrac{\pi}2,~ \dfrac{\pi}2\right]\), the minimum and maximum variation of the heading angle of aircraft \(i\), in radians
  • A safety distance \(D\) between aircraft, in NM (nautical miles)

Time is counted in minutes throughout, so a nominal speed of 200 knots is 200 * KNOT with KNOT one nautical mile per hour expressed in NM/min.

Problem:

Choose the new angles and speeds of the aircraft in given ranges such that the resulting trajectories are conflict-free.

Objective:

Minimize the sum of the squares of the differences in speeds and angles of the aircraft.

Modeling the separation constraint

We denote here for each aircraft \(i\in A\):

  • \(v_i\) the magnitude of modified speed of aircraft \(i\)
  • \(\theta _i\) the modified heading angle of aircraft \(i\)
  • \(q_i\) the scale factor applied to nominal speed of aircraft \(i\)
  • \(\omega _i\) the variation of the heading angle of aircraft \(i\)

Given the set of aircraft \(A\) with initial positions \(\overrightarrow{P_i^0}\) and nominal vectors of velocity \(\overrightarrow{V_i}\), the aircraft deconfliction problem consists in finding new vectors \(\overrightarrow{v_i}\) such that the resulting trajectories are conflict-free, that is, such that \[ \forall i,j \in A,~i<j,~\forall t\ge 0, \qquad \lVert \overrightarrow{p_i}(t) - \overrightarrow{p_j}(t) \rVert \ge D \qquad (1) \]

where \(\overrightarrow{v_i} = (v_i\cos \theta _i, v_i\sin \theta _i)\) is the modified vector of velocity of aircraft \(i\) and \(\overrightarrow{p_i}(t) := \overrightarrow{P_i^0} + t\overrightarrow{v_i}\) is the new position of aircraft \(i\) at instant \(t\ge 0\).

Such a condition cannot be directly plugged into a mathematical programming solver, mainly because of the fact that one of its quantifiers is \(t\), which ranges on a continuous domain. There are several ways of turning \((1)\) into mathematical programming constraints (see “Aircraft deconfliction via Mathematical Programming: Review and insights”, Pelegrín and D’Ambrosio, 2020).

We will use here the “minimum-distance time equations” method which consists of finding, for each pair of aircraft, the critical time instant at which this constraint has to be satisfied. Since distances are positive, we base our analysis on the squared version of \((1)\).

Given a pair of aircraft \(i,j\in A\), the squared distance between \(i\) and \(j\) at time \(t \ge 0\) is

\[ f_{ij} (t)=\lVert \overrightarrow{p_i}(t) - \overrightarrow{p_j}(t) \rVert^2 =\lVert \overrightarrow{v_{ij}} \rVert^2 t^2 + 2 t \langle \overrightarrow{P^0_{ij}} , \overrightarrow{v_{ij}} \rangle + \lVert \overrightarrow{P^0_{ij}} \rVert^2 \qquad \qquad (2) \]

where \(~~\overrightarrow{P^0_{ij}} =\overrightarrow{P^0_i} - \overrightarrow{P^0_j}~~\) and \(~~\overrightarrow{v_{ij}} = \overrightarrow{v_i} - \overrightarrow{v_j}\)

By differentiating \(f_{ij}\), we obtain that the minimum separation between aircraft \(i\) and \(j\) is attained at time \(\qquad t^{\text{min}}_{ij} = \dfrac{- \langle \overrightarrow{P^0_{ij}} , \overrightarrow{v_{ij}} \rangle}{\lVert \overrightarrow{v_{ij}} \rVert^2}\)

If \(t^{\text{min}}_{ij} <0\), the minimum separation between \(i\) and \(j\) was attained in the past, and their trajectories are diverging in the given time horizon. Otherwise, by substituting \(t^{\text{min}}_{ij}\) in \((2)\), we obtain the minimum squared distance between \(i\) and \(j\) during their observed trajectories: \[ f^{\text{min}}_{ij} = \dfrac{- \langle \overrightarrow{P^0_{ij}} , \overrightarrow{v_{ij}} \rangle^2}{\lVert \overrightarrow{v_{ij}} \rVert^2} + \lVert \overrightarrow{P^0_{ij}} \rVert^2 \]

A new separation condition, also equivalent to \((1)\), can be thus stated as follows: \[ \forall i, j \in A,~i<j, \qquad t^{\text{min}}_{ij}<0 \quad \text{ or } \quad f^{\text{min}}_{ij} \ge D^2 \]

\[ \forall i, j \in A,~i<j, \qquad t^{\text{min}}_{ij}<0 \quad \text{ or } \quad \lVert \overrightarrow{v_{ij}} \rVert^2 (\lVert \overrightarrow{P^0_{ij}} \rVert^2 -D^2) - \langle \overrightarrow{P^0_{ij}} , \overrightarrow{v_{ij}} \rangle^2 \ge 0 \qquad (3) \]

We introduce a new variable \(k_{ij}=\left\{ \begin{array}{ll} 1 \text{ if } t^{\text{min}}_{ij} \ge 0\\[.2cm] 0 \text{ otherwise} \end{array} \right.\) so we can rewrite \((3)\) as:

\[ \forall i, j \in A,~i<j, \qquad k_{ij}\left(\lVert \overrightarrow{v_{ij}} \rVert^2 (\lVert \overrightarrow{P^0_{ij}} \rVert^2 -D^2) - \langle \overrightarrow{P^0_{ij}} , \overrightarrow{v_{ij}} \rangle^2 \right) \ge 0 \]

with the constraint checking the sign of \(t^{\text{min}}_{ij}\):

\[ \forall i, j \in A,~i<j, \qquad t^{\text{min}}_{ij} (2k_{ij} -1) \ge 0 \]

If we denote \(\overrightarrow{v_{ij}}=(v_{x,ij},v_{y,ij})\) with \(v_{x,ij}\) and \(v_{y,ij}\) two new variables for each \(i,j \in A\), the previous constraints become:

  • Sign of \(t_{ij}^{\text{min}}\):

\[ \forall i, j \in A,~i<j, \qquad ((X_i - X_j) \cdot v_{x,ij} + (Y_i - Y_j) \cdot v_{y,ij}) \cdot (2 k_{ij} - 1) \le 0 \]

  • Pairwise aircraft separation:

\[ \forall i, j \in A,~i<j, \qquad k_{ij}\left((v_{x,ij} ^ 2 + v_{y,ij} ^ 2) \cdot ((X_i - X_j)^2 + (Y_i - Y_j)^2 -D^2) - ((X_i - X_j) \cdot v_{x,ij} + (Y_i - Y_j) \cdot v_{y,ij})^2 \right) \ge 0 \]

Nonlinear model

Now that we have modeled the separation constraint in the nonlinear programming formalism, we can write the complete model.

Variables

  • For each aircraft \(i\in A\):
    • \(v_i \in \mathbb{R}\) the magnitude of modified speed of aircraft \(i\), in NM/min
    • \(\theta _i \in \mathbb{R}\) the modified heading angle of aircraft \(i\), in radians
    • \(q_i \in [Q_i^{\text{min}},~ Q_i^{\text{max}}]\) the scale factor applied to nominal speed of aircraft \(i\)
    • \(\omega _i \in [\Omega _i^{\text{min}},~ \Omega _i^{\text{max}}]\) the variation of the heading angle of aircraft \(i\)
  • For each pair of aircraft \(i, j\in A\):
    • \(k_{ij} \in \{0, 1\}\) a binary variable which is \(1\) if minimum separation between aircraft \(i\) and \(j\) is attained in the future, else \(0\)
    • \(v_{x,ij},~v_{y,ij} \in \mathbb{R}\) the coordinates of the difference between the modified vectors of velocity of aircraft \(i\) and \(j\) (see above)

Objective: minimize the sum of the squared deviations of the aircraft speeds and heading angles

\[ \min \sum_{i \in A} (q_i-1)^2 + \omega _i ^ 2 \]

Constraints

  • Definition of the speed scale factor \(q_i\)

\[ \forall i \in A, \qquad v_i=q_i\cdot V_i \]

  • Definition of the variation of the heading angle \(\omega _i\)

\[ \forall i \in A, \qquad \theta _i=\Theta _i + \omega _i \]

  • Definition of \(v_x\) and \(v_y\)

\[ \forall i,j \in A,~i<j, \qquad v_{x,ij} = v_i \cdot \cos(\theta _i) - v_j \cdot \cos(\theta _j) \] \[ \forall i,j \in A,~i<j, \qquad v_{y,ij} = v_i \cdot \sin(\theta _i) - v_j \cdot \sin(\theta _j) \]

  • Sign of \(t_{ij}^{\text{min}}\)

\[ \forall i, j \in A,~i<j, \qquad ((X_i - X_j) \cdot v_{x,ij} + (Y_i - Y_j) \cdot v_{y,ij}) \cdot (2 k_{ij} - 1) \le 0 \]

  • Pairwise aircraft separation

\[ \forall i, j \in A,~i<j, \qquad k_{ij}\left((v_{x,ij} ^ 2 + v_{y,ij} ^ 2) \cdot ((X_i - X_j)^2 + (Y_i - Y_j)^2 -D^2) - ((X_i - X_j) \cdot v_{x,ij} + (Y_i - Y_j) \cdot v_{y,ij})^2 \right) \ge 0 \]

Input data

An Aircraft is where it starts, how fast it nominally flies and on what heading, plus how far its speed and heading may be pushed. A Control holds what the solver decides for one aircraft, a speed and a heading together with the two deviations that reach them. An Airspace is a fleet and the min_separation every pair has to keep, and a Resolution is one Control per aircraft together with the deviation the fleet paid.

Speeds are in nautical miles per minute, so KNOT converts from knots, and distances are in nautical miles throughout.

const KNOT = 1 / 60

mutable struct Aircraft
    start::Tuple{Float64,Float64}
    speed::Float64
    heading::Float64
    min_scale::Float64
    max_scale::Float64
    min_turn::Float64
    max_turn::Float64
    Aircraft() = new((0.0, 0.0), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
end

start_x(aircraft::Aircraft) = aircraft.start[1]
start_y(aircraft::Aircraft) = aircraft.start[2]

struct Control
    v::Float64
    theta::Float64
    q::Float64
    omega::Float64
end

velocity_x(control::Control) = control.v * cos(control.theta)
velocity_y(control::Control) = control.v * sin(control.theta)

struct Resolution
    deviation::Float64
    controls::Vector{Control}
end

function Resolution(deviation, v, theta, q, omega)
    return Resolution(
        deviation,
        [
            Control(v_i, theta_i, q_i, omega_i) for
            (v_i, theta_i, q_i, omega_i) in zip(v, theta, q, omega)
        ],
    )
end

mutable struct Airspace
    num_aircraft::Int
    fleet::Vector{Aircraft}
    name::String
    min_separation::Float64
    ray_length::Float64
    xlim::Tuple{Float64,Float64}
    ylim::Tuple{Float64,Float64}
end

function Airspace(num_aircraft::Int)
    return Airspace(
        num_aircraft,
        [Aircraft() for _ in 1:num_aircraft],
        "",
        0.0,
        0.0,
        (0.0, 1.0),
        (0.0, 1.0),
    )
end

We will consider 4 use cases for the problem. The circle and the sector are stress tests rather than pictures of real traffic, with every pair in conflict and every conflict happening at once. The two converging lines and the ten random aircraft are closer to what a controller sees.

using Random

const SKEW = 1 / 100

function fleet_bounds!(airspace::Airspace)
    for aircraft in airspace.fleet
        aircraft.speed = 200 * KNOT
        aircraft.min_scale, aircraft.max_scale = 0.9, 1.1
        aircraft.min_turn, aircraft.max_turn = -pi / 16, pi / 16
    end
    return airspace
end

function load_circle(; num_aircraft=8, ray_length=100, min_separation=5, extent=nothing)
    airspace = Airspace(num_aircraft)
    airspace.name = "Circle air traffic"
    airspace.min_separation = min_separation
    airspace.ray_length = ray_length
    radius = ray_length / 2
    reach = extent === nothing ? radius + 2 * min_separation : extent
    airspace.xlim = airspace.ylim = (-reach, reach)
    fleet_bounds!(airspace)
    for (i, aircraft) in enumerate(airspace.fleet)
        bearing = 2 * pi / num_aircraft * (i - 1)
        aircraft.start = (radius * cos(bearing + SKEW), radius * sin(bearing + SKEW))
        aircraft.heading = pi + bearing
    end
    return airspace
end

function load_sector(;
    num_aircraft=8,
    ray_length=120,
    min_separation=5,
    sector_angle=pi / 2,
    extent=nothing,
)
    airspace = Airspace(num_aircraft)
    airspace.name = "Sector circle air traffic"
    airspace.min_separation = min_separation
    airspace.ray_length = ray_length
    radius = ray_length / 2
    reach = extent === nothing ? radius + 2 * min_separation : extent
    airspace.xlim = airspace.ylim = (-reach, reach)
    fleet_bounds!(airspace)
    for (i, aircraft) in enumerate(airspace.fleet)
        bearing = sector_angle / (num_aircraft + 1) * i
        aircraft.start = (radius * cos(bearing), radius * sin(bearing))
        aircraft.heading = pi + bearing
    end
    return airspace
end

function load_lines(;
    line_size=4, ray_length=150, min_separation=20, spacing=25, standoff=65
)
    airspace = Airspace(2 * line_size)
    airspace.name = "Two converging lines of $line_size aircraft"
    airspace.min_separation = min_separation
    airspace.ray_length = ray_length
    tail = standoff + spacing * (line_size - 1)
    airspace.xlim = (-tail - 3 * min_separation, ray_length)
    airspace.ylim = (-ray_length, tail + 3 * min_separation)
    fleet_bounds!(airspace)
    for (i, aircraft) in enumerate(airspace.fleet)
        if i <= line_size
            aircraft.start = (0.0, standoff + spacing * (i - 1))
            aircraft.heading = 3 * pi / 2
        else
            aircraft.start = (-standoff - spacing * (i - line_size - 1), 0.0)
            aircraft.heading = 0.0
        end
    end
    return airspace
end

function load_random(;
    num_aircraft=10, ray_length=70, min_separation=5, spread=50, seed=9
)
    airspace = Airspace(num_aircraft)
    airspace.name = "$num_aircraft random aircraft"
    airspace.min_separation = min_separation
    airspace.ray_length = ray_length
    reach = spread + 2 * min_separation
    airspace.xlim = airspace.ylim = (-reach, reach)
    fleet_bounds!(airspace)
    rng = MersenneTwister(seed)
    for aircraft in airspace.fleet
        x, y = float(rand(rng, (-spread):spread)), float(rand(rng, (-spread):spread))
        x == 0 && (x = 1.0)
        aircraft.start = (x, y)
        heading = atan(y / x) + rand(rng, -180:180) / 180 * pi / 4
        aircraft.heading = x > 0 ? heading + pi : heading
    end
    return airspace
end

Each aircraft carries a bubble of radius \(D/2\), so two of them are in conflict exactly when their bubbles overlap. The faint dashed ray behind a track is the heading it would have flown had nothing been asked of it, and the figures play the motion out, so the closest approach can be watched rather than inferred.

The circle is eight aircraft spread evenly round its rim, all converging on the center at the same speed. Left alone they arrive together and every bubble overlaps every other.

circle = load_circle()
animate_input(circle; show_circle=true)
Circle air traffic: nominal trajectories, before deconfliction

Model implementation

using JuMP
using KNITRO

minimize_deviation(airspace) builds the model, solves it with Knitro, and returns a Resolution. The objective keyword picks what is paid for. The default charges for both the speed and the heading deviation, and the two later sections charge for one of them alone.

The separation between a pair is nonconvex, and the binary k decides whether the closest approach lies in the future or is already behind them. That makes the model a mixed-integer nonlinear program. Knitro’s MIP multistart is switched on and a node limit keeps the solve time bounded, so what comes back is the best point found rather than a proven optimum.

function minimize_deviation(
    airspace::Airspace, objective="speed+angle"; multistart=true, max_nodes=500
)
    model = Model(KNITRO.Optimizer)
    set_attribute(model, "mip_multistart", Int(multistart))
    set_attribute(model, "mip_maxnodes", max_nodes)

    n = airspace.num_aircraft
    fleet = airspace.fleet
    pairs = [(i, j) for i in 1:n for j in 1:n if i < j]

    @variable(model, v[1:n])

    @variable(
        model,
        fleet[i].heading + fleet[i].min_turn <=
            theta[i in 1:n] <=
            fleet[i].heading + fleet[i].max_turn
    )

    @variable(model, fleet[i].min_scale <= q[i in 1:n] <= fleet[i].max_scale)

    @variable(model, fleet[i].min_turn <= omega[i in 1:n] <= fleet[i].max_turn)

    @variable(model, k[1:length(pairs)], Bin)

    @variable(model, v_x[1:length(pairs)])
    @variable(model, v_y[1:length(pairs)])

    if objective == "speed"
        @objective(model, Min, sum((q[i] - 1)^2 for i in 1:n))
    elseif objective == "angle"
        @objective(model, Min, sum(omega[i]^2 for i in 1:n))
    else
        @objective(model, Min, sum((q[i] - 1)^2 + omega[i]^2 for i in 1:n))
    end

    for i in 1:n
        aircraft = fleet[i]
        @constraint(model, v[i] == aircraft.speed * q[i])
        @constraint(model, theta[i] == aircraft.heading + omega[i])
    end

    for (ij, (i, j)) in enumerate(pairs)
        fi, fj = fleet[i], fleet[j]
        dx = start_x(fi) - start_x(fj)
        dy = start_y(fi) - start_y(fj)

        @constraint(model, v_x[ij] == v[i] * cos(theta[i]) - v[j] * cos(theta[j]))
        @constraint(model, v_y[ij] == v[i] * sin(theta[i]) - v[j] * sin(theta[j]))

        dot = dx * v_x[ij] + dy * v_y[ij]
        speed_sq = v_x[ij]^2 + v_y[ij]^2
        gap_sq = dx^2 + dy^2 - airspace.min_separation^2

        @constraint(model, dot * (2 * k[ij] - 1) <= 0)

        @constraint(model, k[ij] * (speed_sq * gap_sq - dot^2) >= 0)
    end

    optimize!(model)

    deviation = objective_value(model)
    return Resolution(deviation, value.(v), value.(theta), value.(q), value.(omega))
end

Use cases

Circle air traffic

The circle above is unrealistic on purpose. It has served to stress existing resolution methods in order to explore their limits, since every pair of aircraft is in conflict and all of the conflicts happen at the same instant.

circle_resolution = minimize_deviation(circle);
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           116
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        52
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        88        28         0
Number of constraints:                  128 |                           128
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        16         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             8        88           |         8        88          
  quadratic:         16        84        72 |        16        84        72
  nonlinear:          0       364       192 |         0       364       192
  total:             16       480       208 |        16       480       208

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [7e-01, 1e+02] |                [7e-01, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [1e+00, 2e+02] |                [1e+00, 2e+02]
  variable bounds:           [2e-01, 9e+00] |                [2e-01, 9e+00]
  constraint bounds:         [3e+00, 9e+00] |                [3e+00, 9e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    6.72188e-02          3.54063          0.257175       2.668
    1       0.100182          3.29569       6.05678e-02      12.015
    2        3.16667          1.14224          0.738079      12.016
    3        3.20274          1.12502          0.592681      12.016
    4        3.24531          1.11208          0.592666      12.017
    5        3.24729          1.11087          0.592664      12.017
    6        3.24913          1.11042          0.592663      12.018
    7        3.25972          1.10892          0.592661      12.018
    8        3.26034          1.10884          0.592661      12.018
    9        3.26278          1.10862          0.592661      12.019
   10        3.26739          1.10847          0.592661      12.019
   11        3.55745          1.01148           1.99015      12.020
   12        3.57405          1.00875           1.96784      12.021
   13       0.505348          2.28376           161.503      12.025
   14       0.147928          2.43499           103.588      12.026
   15    7.23331e-02          2.49905           40.5840      12.027
   16    7.50926e-02          2.29084           28.9442      12.028
   17    5.31074e-02          2.88087           84.2770      12.029
   18    3.93734e-02          4.11115           83.2938      12.029
   19    3.66123e-02          5.49047           68.0372      12.030
   20    2.95465e-02          4.50380           42.6850      12.030
   30    5.35760e-03          4.22427          0.321597      12.035
   40       0.120275          3.03375          0.202689      12.040
   50       0.122674          3.00132          0.262596      12.044
   60       0.137777          3.00008          0.323085      12.053
   70       0.169631          3.00070          0.310018      12.060
   80       0.202107          3.00047          0.347616      12.065
   90       0.197809          3.00002           1.00001      12.072
  100       0.173090          3.09597           2.39834      12.079
  110       0.233777          3.21218          0.511213      12.087
  120       0.253769          4.27526          0.845448      12.093
  130    4.19282e-02          5.51236           29.6873      12.101
  140    5.18564e-02          1.40888       8.70441e-02      12.106
  150       0.189232          1.35194          0.284203      12.112
  160       0.192742          1.35943          0.295708      12.117
  170       0.109371          273.666           10.0615      12.127
  180       0.112658          219.237           3092.82      12.137
  190    4.67609e-02          1.42147       7.80755e-02      12.143
  200       0.137433         0.962878          0.310872      12.149

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf               12.207

Knitro deduced that the problem is non-convex.

      2       2     0.159118 DURD         -inf               12.296
     19      10     0.117188 FCRD         -inf               12.712
    100      10     0.117188              -inf               17.522
    113      13     0.111862 FCRD         -inf               18.125
    156      14     0.105362 FCRD         -inf               20.372
    200      14     0.105362              -inf               22.826
    300      14     0.105362              -inf               28.157
    346      17     0.104537 FCRD         -inf               30.450
    400      17     0.104537              -inf               33.218
    500      17     0.104537              -inf               38.093

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  1.04537083624540728e-01
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (35.187s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  50442 (3.413s)
# of gradient evaluations           =  46475 (0.672s)
# of hessian evaluations            =  43776 (13.092s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  510 (35.269s)
Total program time (secs)           =  38.09299 (38.088 CPU time)
Time spent in evaluations (secs)    =  17.17750

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.004s
Rounding heuristic                  =  5 / 4 / 0.045s
MPEC heuristic                      =  1 / 0 / 0.006s
Local search heuristic              =  10 / 0 / 0.008s

===========================================================================
Show the full outputHide the full output

Output visualization

report_resolution(circle, circle_resolution)
Circle air traffic, deviation 0.1045

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     194kt   0.970    -6.74°      0.0009     0.0138
       2     196kt   0.981    -5.63°      0.0003     0.0096
       3     199kt   0.996    -6.18°      0.0000     0.0116
       4     201kt   1.007    -6.10°      0.0001     0.0114
       5     200kt   1.002    -8.64°      0.0000     0.0227
       6     209kt   1.043    -0.54°      0.0019     0.0001
       7     217kt   1.087    -6.71°      0.0076     0.0137
       8     180kt   0.900    +1.67°      0.0100     0.0008

Speed changes cost 0.0207 and turns cost 0.0838
animate(circle, circle_resolution; show_circle=true, show_nominal=true)
Circle air traffic: objective 0.105

An intuitive solution would follow a “roundabout” pattern, whereby every aircraft deviates its course by the same angle. Knitro finds something cheaper and far less symmetric. Every aircraft turns the same way, but by very different amounts, and one of them pays with a noticeable change of speed instead. The model is a non-convex mixed-integer nonlinear program and the search stops at the node limit set above, so what you see is the best point found rather than a proven optimum.

The animation shows the speeds as well as the angles. It runs until the last aircraft has left the circle, so the order in which they cross the boundary is the order of their speeds. The ones that accelerated go first and the ones that slowed down are the last to disappear. The faint dashed rays are the nominal headings, kept underneath the solid tracks so that each deviation can be read off directly.

Sector of a circle

This use case is a variant of the circle, with 8 aircraft uniformly distributed on a quarter of the circumference of the circle, all converging on the center of the circle at the same speed.

sector = load_sector()
plot_input(sector; show_circle=true)
Sector circle air traffic: nominal trajectories

Let’s solve it and visualize the solution.

sector_resolution = minimize_deviation(sector);
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           116
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        52
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        88        28         0
Number of constraints:                  128 |                           128
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        16         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             8        88           |         8        88          
  quadratic:         16        84        72 |        16        84        72
  nonlinear:          0       364       192 |         0       364       192
  total:             16       480       208 |        16       480       208

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [1e+00, 5e+01] |                [1e+00, 5e+01]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [5e+00, 1e+02] |                [5e+00, 1e+02]
  variable bounds:           [2e-01, 5e+00] |                [2e-01, 5e+00]
  constraint bounds:         [3e+00, 5e+00] |                [3e+00, 5e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    6.72188e-02          3.12288          0.257175       0.004
    1       0.112848         0.563537       4.89476e-02       0.005
    2       0.135652         0.524107          0.115359       0.005
    3       0.128514         0.495787       8.17697e-02       0.006
    4       0.129066         0.475118       3.39921e-02       0.007
    5       0.160060         0.429708          0.191115       0.007
    6       0.164256         0.416835          0.130177       0.008
    7       0.166564         0.406372       9.28360e-02       0.009
    8       0.174601         0.397475       9.28707e-02       0.009
    9       0.186263         0.384774       9.28515e-02       0.010
   10       0.190239         0.380894       9.28722e-02       0.010
   11       0.208287         0.367969       9.30022e-02       0.011
   12       0.209154         0.366536       9.28548e-02       0.011
   13       0.211561         0.364863       9.30568e-02       0.012
   14       0.212107         0.364503       9.30783e-02       0.012
   15       0.215467         0.362703       9.30857e-02       0.013
   16       0.203050         0.395386           992.552       0.016
   17       0.161823         0.599180           657.264       0.017
   18       0.161165         0.752737           291.627       0.017
   19       0.131711          1.14674           39.4429       0.018
   20       0.129515          1.14534           100.280       0.019
   30    1.59200e-02          4.06067          0.409956       0.024
   40       0.181950         0.335293          0.245706       0.029
   50       0.241832         0.247544          0.525840       0.035
   60       0.271814         0.269771          0.354073       0.041
   70       0.272839         0.268718          0.360512       0.047
   80       0.271512         0.268763          0.362162       0.052
   90       0.273205         0.268763          0.362165       0.057
  100    4.88301e-02         0.681941           1.76959       0.067
  110       0.172026         0.263045       6.24875e-02       0.073
  120       0.253561      6.96614e-02          0.338845       0.078
  130       0.260396      6.57391e-02          0.368594       0.084
  140       0.260397      6.57383e-02          0.368601       0.089
  150       0.245166          9.26053           5.79789       0.099
  160    4.52224e-02          1.60279          0.686233       0.106
  170       0.229788         0.120672          0.225016       0.112
  180       0.259760      6.61621e-02          0.365953       0.117
  190       0.260397      6.57385e-02          0.368599       0.123
  200       0.260397      6.57383e-02          0.368601       0.128

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.177

Knitro deduced that the problem is non-convex.

      2       2     0.170358 DURD         -inf                0.440
    100       2     0.170358              -inf                7.315
    200       2     0.170358              -inf               15.460
    300       1     0.170358              -inf               23.748
    400       1     0.170358              -inf               31.756

EXIT: Satisfactory solution found.

Final Statistics for MIP
------------------------
Final objective value               =  1.70357831420728800e-01
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  402 (31.712s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  68599 (4.694s)
# of gradient evaluations           =  51422 (0.753s)
# of hessian evaluations            =  49266 (4.653s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  408 (31.786s)
Total program time (secs)           =  31.92325 (31.923 CPU time)
Time spent in evaluations (secs)    =  10.09964

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.006s
Rounding heuristic                  =  1 / 0 / 0.025s
MPEC heuristic                      =  1 / 0 / 0.010s
Local search heuristic              =  6 / 0 / 0.004s

===========================================================================
Show the full outputHide the full output
report_resolution(sector, sector_resolution)
Sector circle air traffic, deviation 0.1704

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     180kt   0.900    +8.00°      0.0100     0.0195
       2     180kt   0.901    -1.85°      0.0097     0.0010
       3     194kt   0.970    -3.23°      0.0009     0.0032
       4     186kt   0.929    -9.70°      0.0050     0.0286
       5     207kt   1.037    -3.96°      0.0014     0.0048
       6     198kt   0.988   -10.09°      0.0001     0.0310
       7     220kt   1.100    -4.47°      0.0100     0.0061
       8     210kt   1.051   -10.92°      0.0026     0.0363

Speed changes cost 0.0398 and turns cost 0.1306
animate(sector, sector_resolution; show_circle=true, show_nominal=true)
Sector circle air traffic: objective 0.170

We can see that in this example, changing the headings is not enough, and some aircraft accelerate a lot while others slow down significantly.

Two converging lines

Two lines of four aircraft spaced 25 NM in trail are converging towards each other at the same speed. The safety distance was chosen arbitrarily to be 20 NM. That makes the conflicts between the two lines impossible to resolve by staging alone, without deviating any path. Slotting an aircraft from one line between two consecutive aircraft of the other would need 40 NM of room, and only 25 NM is available.

lines = load_lines()
plot_input(lines)
Two converging lines of 4 aircraft: nominal trajectories
lines_resolution = minimize_deviation(lines);
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           116
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        52
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        88        28         0
Number of constraints:                  128 |                           128
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        16         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             8        76           |         8        76          
  quadratic:         16        72        60 |        16        72        60
  nonlinear:          0       364       180 |         0       364       180
  total:             16       468       196 |        16       468       196

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [1e+00, 1e+02] |                [1e+00, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [5e+01, 3e+02] |                [5e+01, 3e+02]
  variable bounds:           [2e-01, 5e+00] |                [2e-01, 5e+00]
  constraint bounds:         [5e+00, 5e+00] |                [5e+00, 5e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    6.72188e-02          3.54063          0.257175       0.002
    1    7.75496e-02          3.35474          0.231757       0.003
    2    8.19513e-02          3.21520          0.301676       0.004
    3    9.88299e-02          3.17358       7.99092e-03       0.005
    4       0.108494          3.15188       6.43567e-02       0.005
    5       0.114470          3.13906       6.43567e-02       0.006
    6       0.176191          3.01892       6.43567e-02       0.007
    7       0.178041          3.01599       6.43567e-02       0.007
    8       0.182582          3.00905       6.43567e-02       0.008
    9       0.184868          3.00564       6.43567e-02       0.008
   10       0.185920          3.00409       6.43567e-02       0.008
   11       0.186381          3.00342       6.43567e-02       0.009
   12       0.186776          3.00291       6.43567e-02       0.009
   13       0.192102          3.00091       7.86649e-02       0.010
   14       0.191914          3.00090       8.10459e-02       0.010
   15        1.72474          1.79412          0.393306       0.011
   16        1.72453          1.79344           1.20179       0.011
   17       0.265935          2.70494           573.628       0.014
   18    8.96656e-02          2.91996           737.124       0.015
   19    8.94462e-02          5.32968           4316.46       0.016
   20    7.58514e-02          3.65642           413.807       0.017
   30    6.34392e-02          4.15920          0.169906       0.023
   40       0.202403          3.05014          0.284439       0.029
   50       0.242208          3.01612          0.319779       0.037
   60       0.221421          3.00068          0.361088       0.043
   70       0.299582          3.00025          0.370737       0.048
   80       0.361187          3.00013          0.409929       0.054
   90       0.348626          3.00068          0.391890       0.061
  100       0.377180          3.06702           6.87023       0.068
  110       0.351701          4.51520           3.45051       0.074
  120       0.352367          4.51521           1.00317       0.082
  130       0.352367          4.51522          0.551276       0.086
  140    7.66142e-02          5.06342           2.66001       0.096
  150       0.206321          12.1907          0.226657       0.102
  160       0.324940          3.94006          0.178846       0.107
  170       0.310830          4.48594          0.705709       0.113
  180       0.312426          3.77274          0.279723       0.118
  190       0.281655          3.76977          0.412917       0.125
  200       0.285380          3.71071          0.579143       0.132
  300       0.270887         0.948146          0.337764       0.198

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.256

Knitro deduced that the problem is non-convex.

      5       2     0.160126 FCRD         -inf                1.210
      6       3     0.151434 FCRD         -inf                1.309
     46       5     0.134583 FCRD         -inf                4.582
    100       5     0.134583              -inf                9.446
    200       5     0.134583              -inf               18.816
    300       5     0.134583              -inf               28.098
    400       4     0.134583              -inf               37.162
    485       5     0.131180 FCRD         -inf               45.188
    500       5     0.131180              -inf               46.380

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  1.31180492497220413e-01
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (46.100s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  82882 (5.454s)
# of gradient evaluations           =  75676 (1.107s)
# of hessian evaluations            =  72582 (5.869s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  508 (46.203s)
Total program time (secs)           =  46.38002 (46.379 CPU time)
Time spent in evaluations (secs)    =  12.42971

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.006s
Rounding heuristic                  =  4 / 4 / 0.024s
MPEC heuristic                      =  1 / 0 / 0.010s
Local search heuristic              =  9 / 0 / 0.007s

===========================================================================
Show the full outputHide the full output
report_resolution(lines, lines_resolution)
Two converging lines of 4 aircraft, deviation 0.1312

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     220kt   1.100   +10.10°      0.0100     0.0311
       2     184kt   0.919    -5.52°      0.0065     0.0093
       3     201kt   1.007    +1.92°      0.0001     0.0011
       4     217kt   1.087    +6.88°      0.0075     0.0144
       5     181kt   0.905    +2.33°      0.0090     0.0017
       6     205kt   1.023    -6.34°      0.0005     0.0122
       7     182kt   0.911    +6.97°      0.0079     0.0148
       8     190kt   0.952    +2.98°      0.0023     0.0027

Speed changes cost 0.0438 and turns cost 0.0874
animate(lines, lines_resolution; show_nominal=true)
Two converging lines of 4 aircraft: objective 0.131

Ten random aircraft

In this use case, a set of 10 aircraft flying at a nominal speed of 200 knots was positioned and oriented at random. This initial configuration generates conflicts that have to be avoided.

scattered = load_random()
plot_input(scattered)
10 random aircraft: nominal trajectories
scattered_resolution = minimize_deviation(scattered);
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    175 |                           175
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        75 |         0         0        75
                             free     fixed |                free     fixed
                              100         0 |                 100         0
                  cont.    binary   integer |     cont.    binary   integer
                    130        45         0 |       130        45         0
Number of constraints:                  200 |                           200
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            20         0         0 |        20         0         0
  quadratic:          0        45         0 |         0        45         0
  nonlinear:         90        45         0 |        90        45         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10       130           |        10       130          
  quadratic:         20       135       110 |        20       135       110
  nonlinear:          0       585       300 |         0       585       300
  total:             20       760       320 |        20       760       320

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [1e+00, 1e+02] |                [1e+00, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [4e+00, 2e+02] |                [4e+00, 2e+02]
  variable bounds:           [1e-01, 5e+00] |                [1e-01, 5e+00]
  constraint bounds:         [7e-02, 4e+00] |                [7e-02, 4e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    5.78517e-02          3.50966          0.283161       0.003
    1       0.108513          3.21734          0.174435       0.004
    2        5.20812         0.771571          0.363942       0.005
    3        5.24085         0.760382          0.169102       0.006
    4        5.26608         0.752906          0.147678       0.007
    5        5.29380         0.746346          0.646228       0.008
    6        5.31483         0.741860          0.644595       0.009
    7        5.32653         0.740448          0.643375       0.010
    8        5.35552         0.736227          0.642738       0.011
    9        1.32975          1.97011           276.082       0.015
   10       0.212147          2.62163           100.223       0.016
   11    9.35060e-02          5.45793           190.248       0.018
   12    9.31095e-02          2.65913           328.768       0.019
   13       0.151613          11.0968           195.821       0.020
   14       0.145621          11.0473           165.378       0.022
   15       0.113608          170.205           96.6601       0.023
   16       0.128919          166.674           170.887       0.024
   17       0.129938          151.593           171.490       0.025
   18       0.138274          44.2650           157.028       0.026
   19       0.130162          2.36871           81.7029       0.027
   20    9.92052e-02          2.82132           50.7336       0.028
   30    2.71777e-03          15.7965           35.8772       0.034
   40       0.210107          3.56185          0.132312       0.041
   50       0.312771          3.14269          0.167840       0.049
   60       0.369084          3.02549          0.334520       0.056
   70       0.436202          3.18051          0.542480       0.064
   80       0.461637          3.41303          0.358562       0.071
   90       0.481939          3.42142          0.628917       0.080
  100       0.485524          3.42222          0.378856       0.087
  110       0.486496          3.41256           12.2216       0.098
  120       0.105822          4.42356           12.5266       0.111
  130       0.290364          3.94042       9.94445e-02       0.119
  140       0.378266          3.80940          0.484296       0.128
  150       0.375030          5.09472          0.251148       0.139
  160       0.381267          5.10549          0.264279       0.147
  170       0.381267          5.10549          0.264280       0.156
  180       0.244895          206.693           78.2108       0.172
  190       0.253812          143.443           696.281       0.188
  200    7.24138e-02          1.47544           2.47650       0.200

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.303

Knitro deduced that the problem is non-convex.

      2       2  4.57177e-02 FCRD         -inf                0.618
     19      13  2.23971e-02 FCRD         -inf                1.076
     76      15  2.10437e-02 FCRD         -inf                7.172
    100      15  2.10437e-02              -inf                9.870
    200      15  2.10437e-02              -inf               21.588
    300      15  2.10437e-02              -inf               32.061
    400      15  2.10437e-02              -inf               42.481
    500      15  2.10437e-02              -inf               53.041

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  2.10437182637335241e-02
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (52.694s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  66591 (7.358s)
# of gradient evaluations           =  56572 (1.282s)
# of hessian evaluations            =  53640 (7.308s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  507 (52.812s)
Total program time (secs)           =  53.04152 (53.040 CPU time)
Time spent in evaluations (secs)    =  15.94811

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.006s
Rounding heuristic                  =  3 / 3 / 0.019s
MPEC heuristic                      =  1 / 0 / 0.014s
Local search heuristic              =  8 / 0 / 0.019s

===========================================================================
Show the full outputHide the full output
report_resolution(scattered, scattered_resolution)
10 random aircraft, deviation 0.0210

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     200kt   1.000    -0.00°      0.0000     0.0000
       2     189kt   0.947    +0.20°      0.0028     0.0000
       3     208kt   1.040    -1.11°      0.0016     0.0004
       4     190kt   0.952    +1.05°      0.0023     0.0003
       5     199kt   0.993    -3.31°      0.0001     0.0033
       6     200kt   1.000    +0.00°      0.0000     0.0000
       7     210kt   1.050    -5.02°      0.0025     0.0077
       8     200kt   1.000    +0.00°      0.0000     0.0000
       9     202kt   1.008    +0.17°      0.0001     0.0000
      10     200kt   1.000    +0.00°      0.0000     0.0000

Speed changes cost 0.0093 and turns cost 0.0117
animate(scattered, scattered_resolution; show_nominal=true)
10 random aircraft: objective 0.021

With ten aircraft the faint dashed headings earn their keep. The ones that never conflicted with anyone are easy to pick out, since they did not change speed or direction and their solid track lies straight on top of the dashed one.

Model extensions

The goal of this section is to show how the solutions change when we change the objective function.

Objective only taking into account the changes in speed

The new objective function is to minimize the sum of the squared differences in the aircraft speeds (rather than the heading angles).

\[ \min \sum_{i \in A} (q_i-1)^2 \]

The heading angles can still be adjusted; they are simply not considered in the objective function.

circle_speed = minimize_deviation(circle, "speed");
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 1 variable (1%) and 1 constraint (1%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           115
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         1         0        50
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        87        28         0
Number of constraints:                  128 |                           127
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        15         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             8        88           |         8        86          
  quadratic:          8        84        64 |         8        84        64
  nonlinear:          0       364       192 |         0       364       192
  total:              8       480       200 |         8       478       200

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [7e-01, 1e+02] |                [7e-01, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [1e+00, 2e+02] |                [1e+00, 2e+02]
  variable bounds:           [2e-01, 9e+00] |                [2e-01, 9e+00]
  constraint bounds:         [3e+00, 9e+00] |                [3e+00, 8e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    1.45418e-02          3.54063       3.10810e-02       0.002
    1    5.19648e-02          3.29569       1.03427e-02       0.003
    2        3.14434          1.14224          0.228421       0.004
    3        3.18763          1.12475          0.228383       0.005
    4        3.23076          1.11165          0.228238       0.005
    5        3.23619          1.11009          0.228220       0.006
    6        3.24073          1.10873          0.228205       0.006
    7        3.24076          1.10871          0.228204       0.007
    8        3.25752          1.10209          0.416178       0.008
    9        3.25752          1.10204          0.417866       0.008
   10        3.32814          1.07582          0.966317       0.009
   11        3.32847          1.07540          0.965880       0.010
   12        3.32991          1.07460          0.965042       0.010
   13        3.33028          1.07439          0.964827       0.011
   14        3.33161          1.07374          0.964153       0.011
   15        3.33202          1.07334          0.963735       0.012
   16        3.33217          1.07304          0.963421       0.012
   17        3.33249          1.07277          0.963143       0.013
   18        3.33267          1.07263          0.962994       0.013
   19        3.33352          1.07175          0.962078       0.014
   20        3.33392          1.07129          0.961599       0.014
   30    2.37628e-03          6.54262           42.0037       0.023
   40    2.89851e-03          5.46212          0.532703       0.028
   50    7.65595e-02          3.01653          0.115204       0.033
   60    7.97516e-02          3.00142          0.581047       0.040
   70    7.99820e-02          3.00083          0.343723       0.048
   80    7.99821e-02          3.18187           6.81848       0.054
   90    7.99786e-02          3.17512           43.0317       0.062
  100    7.99784e-02          3.41540          0.920719       0.070
  110    7.99777e-02          4.22112           5.15029       0.077
  120    7.99471e-02          4.65585           3.29023       0.082
  130       0.143272          5.25325           5654.57       0.089
  140    2.91638e-02          5.69935           7.93333       0.095
  150    6.36936e-02          5.62310       5.63813e-02       0.101
  160    7.23134e-02          5.55429       9.62196e-02       0.107
  170    7.23134e-02          5.55429       9.61947e-02       0.113
  180    4.87612e-02          368.490           19.0094       0.124
  190    6.65134e-02          135.121           1156.61       0.135
  200    2.96405e-02          1.56080       9.99740e-02       0.141

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.202

Knitro deduced that the problem is non-convex.

      2       2  3.79830e-02 DURD         -inf                0.337
      6       4  3.17609e-02 FCRD         -inf                0.487
      9       5  3.55271e-15 FCRD         -inf                0.575
    100       5  3.55271e-15              -inf                7.188
    200       5  3.55271e-15              -inf               14.875
    300       4  3.55271e-15              -inf               21.324
    400       4  3.55271e-15              -inf               27.296
    500       3  3.55271e-15              -inf               34.709

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  3.55271367880050093e-15
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (34.449s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  58420 (3.988s)
# of gradient evaluations           =  51917 (4.007s)
# of hessian evaluations            =  49236 (4.140s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  508 (34.534s)
Total program time (secs)           =  34.70938 (34.708 CPU time)
Time spent in evaluations (secs)    =  12.13419

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.005s
Rounding heuristic                  =  3 / 2 / 0.040s
MPEC heuristic                      =  1 / 0 / 0.009s
Local search heuristic              =  8 / 0 / 0.008s

===========================================================================
Show the full outputHide the full output
report_resolution(circle, circle_speed)
Circle air traffic, deviation 0.0000

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     200kt   1.000    -9.44°      0.0000     0.0271
       2     200kt   1.000    -9.37°      0.0000     0.0268
       3     200kt   1.000    -9.81°      0.0000     0.0293
       4     200kt   1.000    -9.39°      0.0000     0.0268
       5     200kt   1.000    -9.43°      0.0000     0.0271
       6     200kt   1.000    -9.63°      0.0000     0.0283
       7     200kt   1.000    -9.51°      0.0000     0.0276
       8     200kt   1.000   -10.15°      0.0000     0.0314

Speed changes cost 0.0000 and turns cost 0.2244
animate(circle, circle_speed; show_circle=true, show_nominal=true)
Circle air traffic: objective 0.000

Objective only taking into account the changes in heading angle

The new objective function is to minimize the sum of the squared differences in the aircraft heading angles (rather than the speeds).

\[ \min \sum_{i \in A} \omega _i ^ 2 \]

The speeds can still be adjusted; they are simply not considered in the objective function.

circle_angle = minimize_deviation(circle, "angle");
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           116
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        52
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        88        28         0
Number of constraints:                  128 |                           128
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        16         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        88           |         0        88          
  quadratic:          8        84        64 |         8        84        64
  nonlinear:          0       364       192 |         0       364       192
  total:              8       480       200 |         8       480       200

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [7e-01, 1e+02] |                [7e-01, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [1e+00, 2e+02] |                [1e+00, 2e+02]
  variable bounds:           [2e-01, 9e+00] |                [2e-01, 9e+00]
  constraint bounds:         [3e+00, 9e+00] |                [3e+00, 9e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    5.26770e-02          3.54063          0.257175       0.002
    1    4.82175e-02          3.29569       5.96041e-02       0.003
    2    2.10935e-02          1.14212          0.702056       0.004
    3    1.23964e-02          1.12496          0.183246       0.004
    4    9.92801e-03          1.11194          0.134726       0.005
    5    7.29465e-03          1.10251          0.564974       0.006
    6    7.46382e-03          1.10199          0.564708       0.006
    7    6.60931e-03          1.09900          0.563273       0.007
    8    2.20889e-02          2.28377           51.7832       0.010
    9    6.81079e-02          8.76824           59.9695       0.010
   10    6.05663e-02          2.61709           49.1633       0.011
   11    2.03799e-02          9.41288           26.9507       0.012
   12    7.50253e-02          13.1590           9.93056       0.013
   13    3.62005e-02          4.06117           3.86961       0.014
   14    3.27233e-02          3.51610           15.4852       0.015
   15    2.78475e-02          4.32539           12.4341       0.015
   16    1.88123e-02          5.79541           2.88415       0.016
   17    9.71779e-03          7.12891          0.966854       0.016
   18    5.50564e-03          7.24259           2.34104       0.016
   19    2.37572e-05          7.53239           1.05143       0.017
   20    1.69350e-05          7.10993           1.17333       0.017
   30    3.87644e-02          3.00907          0.154736       0.022
   40    5.70515e-02          3.37510          0.323245       0.026
   50       0.110739          3.00407          0.340834       0.031
   60    9.71554e-02          3.00490          0.316685       0.036
   70       0.213902          3.06732          0.962980       0.043
   80       0.195995          4.19685           3.65054       0.049
   90       0.195744          5.08596          0.926179       0.055
  100       0.173951          5.64284           3.07860       0.061
  110       0.144693          5.94055           1.20528       0.068
  120       0.106139          6.15259           1.36421       0.073
  130       0.100639          6.12617          0.295429       0.077
  140    1.42762e-02          6.12565          0.475445       0.084
  150    9.37876e-02          6.10896          0.289775       0.089
  160       0.100794          6.12621          0.295344       0.094
  170       0.101446          6.12621          0.295343       0.100
  180    7.84576e-02          332.315           20.0168       0.112
  190    8.70612e-02          202.158           1679.94       0.121
  200    1.21461e-02         0.973926           2.98301       0.128

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.189

Knitro deduced that the problem is non-convex.

      2       2  9.59858e-02 FCRD         -inf                0.341
     35      12  8.74859e-02 FCRD         -inf                1.549
     78      13  7.52755e-02 FCRD         -inf                4.241
    100      13  7.52755e-02              -inf                5.546
    200      13  7.52755e-02              -inf               11.303
    300      13  7.52755e-02              -inf               17.274
    400      12  7.52755e-02              -inf               23.259
    500      12  7.52755e-02              -inf               30.421

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  7.52754803790306876e-02
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (30.191s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  57403 (3.907s)
# of gradient evaluations           =  51014 (0.783s)
# of hessian evaluations            =  48315 (4.001s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  508 (30.243s)
Total program time (secs)           =  30.42140 (30.420 CPU time)
Time spent in evaluations (secs)    =  8.69053

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.005s
Rounding heuristic                  =  3 / 3 / 0.016s
MPEC heuristic                      =  1 / 0 / 0.008s
Local search heuristic              =  8 / 0 / 0.005s

===========================================================================
Show the full outputHide the full output
report_resolution(circle, circle_angle)
Circle air traffic, deviation 0.0753

aircraft     speed   scale      turn  speed cost  turn cost
-----------------------------------------------------------
       1     200kt   1.002    +1.18°      0.0000     0.0004
       2     180kt   0.900    -0.34°      0.0100     0.0000
       3     200kt   0.998    -8.41°      0.0000     0.0216
       4     198kt   0.989    -6.60°      0.0001     0.0133
       5     200kt   1.000    -5.83°      0.0000     0.0104
       6     202kt   1.009    -6.83°      0.0001     0.0142
       7     220kt   1.100    +2.60°      0.0100     0.0021
       8     180kt   0.900    -6.63°      0.0100     0.0134

Speed changes cost 0.0302 and turns cost 0.0753
animate(circle, circle_angle; show_circle=true, show_nominal=true)
Circle air traffic: objective 0.075

We can now compare the solutions obtained with the new objectives to the previous ones.

animate_comparison(
    circle,
    [circle_resolution, circle_speed, circle_angle];
    show_circle=true,
    show_nominal=true,
)
speed+angle: 0.105
speed: 0.000
angle: 0.075

From left to right, the initial objective, the minimization of speed, and the minimization of angle.

We can see that if we only minimize the speeds, the aircraft keep their nominal speed exactly, for an objective of 0, and pay for it with heading changes close to the largest ones allowed, leaving the fleet almost symmetric. If we minimize only the heading angles, the deviations shrink and the aircraft adjust their speeds instead.

Here is the comparison on another example.

lines_speed = minimize_deviation(lines, "speed");
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 4 variables (3%) and 4 constraints (3%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           112
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        48
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        84        28         0
Number of constraints:                  128 |                           124
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        12         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             8        76           |         8        68          
  quadratic:          8        72        52 |         8        72        52
  nonlinear:          0       364       180 |         0       364       180
  total:              8       468       188 |         8       460       188

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [2e+00, 2e+00] |                [2e+00, 2e+00]
  linear constraints:        [1e+00, 1e+02] |                [1e+00, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [5e+01, 3e+02] |                [5e+01, 3e+02]
  variable bounds:           [2e-01, 5e+00] |                [2e-01, 5e+00]
  constraint bounds:         [5e+00, 5e+00] |                [5e+00, 5e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    1.45418e-02          3.54063       4.13890e-02       0.005
    1    3.73919e-02          3.35474       7.03742e-02       0.006
    2    8.10047e-02          3.21524       4.82246e-02       0.007
    3    9.95160e-02          3.17349       2.46878e-02       0.007
    4       0.115326          3.14041       2.46607e-02       0.008
    5       0.116868          3.13410       2.46065e-02       0.009
    6    6.06150e-02          3.10141           501.595       0.012
    7    6.57510e-02          3.04217           241.022       0.012
    8    5.87079e-02          3.05790           65.8467       0.013
    9    5.70787e-02          3.07258           25.9031       0.014
   10    5.43009e-02          3.12400           9.46803       0.015
   11    5.45696e-02          3.12398           2.28203       0.016
   12    5.33813e-02          20.1568           39.4827       0.017
   13    5.29788e-02          3.17809           9.66822       0.018
   14    6.24974e-02          3.16136           11.4455       0.019
   15    5.86858e-02          3.17503           4.64860       0.019
   16    5.58987e-02          3.20478           4.13894       0.020
   17    5.37912e-02          3.44643           3.27600       0.020
   18    5.14921e-02          4.05703           2.81915       0.021
   19    5.00565e-02          4.33924           7.74166       0.022
   20    6.24937e-02          4.26343          0.234903       0.022
   30    7.90515e-02          4.03205       7.80277e-02       0.027
   40    7.96474e-02          4.12306          0.159775       0.035
   50    7.99288e-02          4.12203       1.73602e-03       0.041
   60    7.99972e-02          4.12182       9.08496e-04       0.046
   70    8.00000e-02          4.12181       9.03046e-04       0.051
   80       0.239645          3.51401           4.41885       0.061
   90    8.01765e-02          4.12041          0.171894       0.069
  100    7.99988e-02          4.12182       4.91948e-03       0.076
  110    8.00000e-02          4.12181       1.06906e-03       0.082
  120    8.00000e-02          4.12181       1.40439e-02       0.088
  130    3.78380e-02          1005.84           823.201       0.102
  140    3.90262e-02          461.144           2151.03       0.113
  150    2.87227e-02         0.904555           1947.72       0.125
  160    3.59581e-02         0.960793       8.44314e-02       0.131
  170    7.89498e-02         0.774691       3.58371e-02       0.136
  180    7.98760e-02         0.898706          0.172859       0.143
  190    7.99559e-02         0.909398          0.298114       0.153
  200    7.83407e-02         0.835443          0.646513       0.162
  300    7.00305e-02         0.667219       1.10519e-02       0.234

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.248

Knitro deduced that the problem is non-convex.

     12       2  8.92649e-03 FCRD         -inf                3.245
    100       2  8.92649e-03              -inf               12.122
    200       2  8.92649e-03              -inf               22.222
    300       1  8.92649e-03              -inf               33.049
    400       1  8.92649e-03              -inf               44.370

EXIT: Satisfactory solution found.

Final Statistics for MIP
------------------------
Final objective value               =  8.92648763319581207e-03
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  412 (45.436s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  73982 (5.029s)
# of gradient evaluations           =  66165 (4.944s)
# of hessian evaluations            =  63170 (5.138s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  417 (45.506s)
Total program time (secs)           =  45.66663 (45.665 CPU time)
Time spent in evaluations (secs)    =  15.11145

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.005s
Rounding heuristic                  =  1 / 1 / 0.012s
MPEC heuristic                      =  1 / 0 / 0.010s
Local search heuristic              =  6 / 0 / 0.011s

===========================================================================
Show the full outputHide the full output
lines_angle = minimize_deviation(lines, "angle");
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro changing mip_method from AUTO to 1.
No start point provided -- Knitro computing one.

Knitro presolve eliminated 0 variables (0%) and 0 constraints (0%) in 0.00s.

datacheck                0
feastol                  1e-06
feastol_abs              1e-06
hessian_no_f             1
mip_maxnodes             500
mip_multistart           1
mip_numthreads           1
ms_numthreads            1
numthreads               1
opttol                   1e-06
opttol_abs               0.001
Knitro changing mip_root_nlpalg from AUTO to 1.
Knitro changing mip_node_nlpalg from AUTO to 1.
Knitro changing mip_branchrule from AUTO to 2.
Knitro changing mip_selectrule from AUTO to 2.
Knitro changing mip_mir from AUTO to 2.
Knitro changing mip_clique from AUTO to 0.
Knitro changing mip_zerohalf from AUTO to 0.
Knitro changing mip_liftproject from AUTO to 0.
Knitro changing mip_knapsack from AUTO to 2.
Knitro changing mip_gomory from AUTO to 0.
Knitro changing mip_cut_flowcover from AUTO to 2.
Knitro changing mip_cut_probing from AUTO to 1.
Knitro changing mip_rounding from AUTO to 3.
Knitro changing mip_heuristic_strategy from AUTO to 1.
Knitro changing mip_heuristic_feaspump from AUTO to 1.
Knitro changing mip_heuristic_misqp from AUTO to 0.
Knitro changing mip_heuristic_mpec from AUTO to 1.
Knitro changing mip_heuristic_diving from AUTO to 1926.
Knitro changing mip_heuristic_fixpropagate from AUTO to 62.
Knitro changing mip_heuristic_lns from AUTO to 0.
Knitro changing mip_heuristic_localsearch from AUTO to 1.
Knitro changing mip_pseudoinit from AUTO to 1.
WARNING: Problem appears to have nonlinear equalities and be non-convex.
         The Knitro mixed integer solver is designed for convex problems.
         For non-convex problems it is only a heuristic, and the reported
         bounds and optimality claims cannot be verified.


Problem Characteristics                     |           Presolved
-----------------------
Problem type: MINLP
Objective: minimize / quadratic
Number of variables:                    116 |                           116
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        52 |         0         0        52
                             free     fixed |                free     fixed
                               64         0 |                  64         0
                  cont.    binary   integer |     cont.    binary   integer
                     88        28         0 |        88        28         0
Number of constraints:                  128 |                           128
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            16         0         0 |        16         0         0
  quadratic:          0        28         0 |         0        28         0
  nonlinear:         56        28         0 |        56        28         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        76           |         0        76          
  quadratic:          8        72        52 |         8        72        52
  nonlinear:          0       364       180 |         0       364       180
  total:              8       468       188 |         8       468       188

Knitro using Branch and Bound method with 1 thread.

Initial points
--------------
No initial point provided for the root node relaxation.
No primal point provided for the MIP.

Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [1e+00, 1e+02] |                [1e+00, 1e+02]
  quadratic objective:       [1e+00, 1e+00] |                [1e+00, 1e+00]
  quadratic constraints:     [5e+01, 3e+02] |                [5e+01, 3e+02]
  variable bounds:           [2e-01, 5e+00] |                [2e-01, 5e+00]
  constraint bounds:         [5e+00, 5e+00] |                [5e+00, 5e+00]

Root node relaxation
--------------------

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0    5.26770e-02          3.54063          0.257175       0.003
    1    4.01587e-02          3.35474          0.229253       0.003
    2    9.20997e-04          3.21527       4.17678e-02       0.004
    3    4.93176e-05          3.17365       8.64113e-03       0.005
    4    4.39379e-05          3.14062       8.63099e-03       0.005
    5    4.38107e-05          3.13227       8.62887e-03       0.006
    6    4.39476e-05          3.12933       9.04633e-03       0.006
    7    4.65794e-05          3.12641       1.07590e-02       0.006
    8    1.50100e-03          3.11605       1.14343e-02       0.007
    9    1.51147e-03          3.11587       1.16989e-02       0.008
   10    1.95582e-03          3.11502       2.22809e-02       0.008
   11    1.77754e-02          3.03440       4.23211e-02       0.009
   12    2.41939e-02          3.03401       7.16238e-02       0.009
   13    2.67764e-02          3.03310       5.64285e-02       0.010
   14    3.34906e-02          2.76246       6.60677e-02       0.011
   15    3.45595e-02          2.76236       7.01969e-02       0.011
   16    4.21641e-02          2.76184       9.73138e-02       0.011
   17    4.69802e-02          2.76150          0.117850       0.012
   18    5.27271e-02          2.76104          0.144438       0.012
   19    7.18592e-02          2.76004          0.207980       0.013
   20    7.22881e-02          2.75949          0.112073       0.013
   30    4.80492e-03          3.62229           11.1314       0.023
   40    7.95252e-03          4.03828          0.125040       0.027
   50       0.245115          3.17919          0.176294       0.031
   60       0.303816          3.24752           1.10154       0.039
   70       0.306485          3.24905          0.180578       0.044
   80       0.308360          3.24929       7.79261e-02       0.048
   90       0.308423          3.24931       7.73327e-05       0.053
  100       0.308425          3.24931       7.53820e-04       0.057
  110       0.308425          3.24931           128.620       0.064
  120       0.255160          2.79171           5465.08       0.074
  130    2.63550e-02          1.12227           26.6158       0.081
  140       0.214042         0.909520          0.174481       0.086
  150       0.261350         0.688403          0.284920       0.093
  160       0.276936         0.645614          0.444670       0.101
  170       0.256760         0.642514          0.314587       0.107
  180       0.257425         0.641402          0.341307       0.114
  190       0.257612         0.641332          0.418131       0.120
  200       0.221759         0.641332          0.267869       0.125
  300       0.219575          1787.22           167.493       0.194

Tree search
-----------

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       1                           -inf                0.244

Knitro deduced that the problem is non-convex.

      8       2     0.111754 FCRD         -inf                1.943
     48       3  8.28300e-02 FCRD         -inf                5.910
     83       4  8.08092e-02 FCRD         -inf                9.113
    100       4  8.08092e-02              -inf               10.664
    200       4  8.08092e-02              -inf               20.047
    300       4  8.08092e-02              -inf               29.304
    400       4  8.08092e-02              -inf               39.180
    500       4  8.08092e-02              -inf               48.275

EXIT: Node limit reached. Integer feasible point found.

Final Statistics for MIP
------------------------
Final objective value               =  8.08091971167578388e-02
Final bound value                   =  -inf
Final optimality gap (abs / rel)    =  inf / inf
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  500 (47.933s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  85456 (5.678s)
# of gradient evaluations           =  77068 (1.164s)
# of hessian evaluations            =  73873 (6.080s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  507 (48.088s)
Total program time (secs)           =  48.27524 (48.274 CPU time)
Time spent in evaluations (secs)    =  12.92234

Cuts statistics (gen / add)
---------------------------
Knapsack cuts                       =  0 / 0
Mixed-integer rounding cuts         =  0 / 0
Flow-cover cuts                     =  0 / 0
Probing cuts                        =  0 / 0

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.006s
Rounding heuristic                  =  3 / 3 / 0.081s
MPEC heuristic                      =  1 / 0 / 0.010s
Local search heuristic              =  8 / 0 / 0.006s

===========================================================================
Show the full outputHide the full output
animate_comparison(
    lines, [lines_resolution, lines_speed, lines_angle]; show_nominal=true
)
speed+angle: 0.131
speed: 0.009
angle: 0.081

We do not see in this example a significant change in the flight paths, but we still observe that, depending on what we minimize, the results are different, and the aircraft do not cross the opposite line in the same order.

References

  • “Aircraft deconfliction via Mathematical Programming: Review and insights” - Mercedes Pelegrín, Claudia d’Ambrosio (2020)
  • “Resolution of Conflicts Involving Many Aircraft via Semidefinite Programming” - E. Frazzoli, Z.-H. Mao, J.-H. Oh, E. Feron (1999)
 

Solved with Artelys Knitro · artelys.com