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

On this page

  • Introduction
  • Problem description
  • Input data
  • Solving a model
  • The Markowitz model
    • Varying the desired return
  • Adding diversification bounds
  • Adding a cardinality limit
  • Rebalancing with transaction costs
  • Optimizing portfolios with a large number of assets

Portfolio Optimization

Allocate capital across assets to minimize risk at a target return, the convex Markowitz model, then extend it with diversification, cardinality and transaction-cost constraints.

Notebook
Python / Knitro API Python / Pyomo Julia / JuMP

Introduction

We consider the portfolio optimization problem, where an investor aims to allocate capital among \(N\) assets within a single period. Portfolio optimization is a fundamental concept in finance that focuses on balancing risk and return. The objective is to determine the optimal weights to assign to each asset in the portfolio.

The curve on the left is the best risk attainable at each desired return, and the bars on the right show the allocation the model picks at one point on it.

Problem description

There are multiple variants of portfolio optimization problems. We start with the most fundamental one, the Markowitz model, and take the others in turn, each one adding to the last.

Input

  • \(N\) assets; for each asset \(i\), its expected return \(\mu_i\)
  • A desired return \(R\)
  • For each pair of assets \((i, j)\), their covariance \(\Sigma_{ij}\)

Problem: find for each asset, the proportion of the capital invested in it, such that the desired return is met.

Objective: minimize the risk \(w^\top \Sigma w\), where \(w\) represents the vector of allocations.

Input data

We retrieve realistic input data from nasdaq.com. A Market holds a name for each asset, its expected return, and the covariance between every pair. A Portfolio holds the weight given to each asset, together with the return and the risk that follow from it.

function expected_return(mu, weights)
    return sum(m * w for (m, w) in zip(mu, weights))
end

function risk(sigma, weights)
    indices = eachindex(weights)
    return sum(sigma[i, j] * weights[i] * weights[j] for i in indices, j in indices)
end

struct Market
    name::String
    names::Vector{String}
    returns::Vector{Float64}
    covariance::Matrix{Float64}
end

num_assets(market::Market) = length(market.names)

assets(market::Market) = 1:num_assets(market)

struct Portfolio
    weights::Vector{Float64}
    expected_return::Float64
    risk::Float64
end

A market too large to write out lives in a file. load_market reads one CSV from shared/data with one row per asset, holding its name, its expected return, and then its covariance with every asset in turn. That is where the hundred-asset market at the end of the page comes from.

const DATA_DIR = joinpath("shared", "data")

function load_market(file_name, name)
    lines = eachline(joinpath(DATA_DIR, file_name))
    rows = [split(strip(line), ',') for (i, line) in enumerate(lines) if i > 1]
    names = [String(row[1]) for row in rows]
    returns = [parse(Float64, row[2]) for row in rows]
    indices = eachindex(rows)
    covariance = [parse(Float64, rows[i][j + 2]) for i in indices, j in indices]
    return Market(name, names, returns, covariance)
end

The worked example is ten companies from the NASDAQ. It is small enough to write out in full, so the numbers the model is given stay in plain sight.

names = [
    "Facebook",
    "Intel",
    "Frontier",
    "Micron",
    "Apple",
    "Qualcomm",
    "Sirius",
    "App. Mat.",
    "Cisco",
    "Yahoo",
]

mu = [
    8.68097,
    -6.08624,
    -66.84089,
    -69.02419,
    -0.61631,
    10.46047,
    7.63278,
    20.49615,
    -0.257636,
    19.25747,
]

sigma = [
    1.75 0.38 0.54 0.63 -0.14 0.29 -0.15 -0.19 0.06 0.10
    0.38 1.74 0.75 2.13 -0.14 0.30 0.86 0.24 0.28 0.47
    0.54 0.75 6.85 0.31 -0.01 0.84 -0.14 0.71 0.50 0.95
    0.63 2.13 0.31 10.31 0.48 0.27 0.23 0.50 -0.02 0.47
    -0.14 -0.14 -0.01 0.48 1.24 -0.02 0.12 0.15 -0.10 0.46
    0.29 0.30 0.84 0.27 -0.02 1.08 0.54 0.38 0.54 0.75
    -0.15 0.86 -0.14 0.23 0.12 0.54 0.97 0.49 0.44 0.60
    -0.19 0.24 0.71 0.50 0.15 0.38 0.49 2.35 0.46 0.86
    0.06 0.28 0.50 -0.02 -0.10 0.54 0.44 0.46 0.84 0.37
    0.10 0.47 0.95 0.47 0.46 0.75 0.60 0.86 0.37 3.16
]

nasdaq = Market("Ten companies from the NASDAQ", names, mu, sigma)

Five of the ten have a negative expected return. A model free to leave them out will, and the ones it does hold are those whose covariances let them offset each other.

draw_market(nasdaq, "Ten companies from the NASDAQ")

The bars are \(\mu\) and the grid is \(\Sigma\), over the same assets in the same order. The diagonal of \(\Sigma\) is each asset’s own variance, not the risk \(w^\top \Sigma w\) the model minimizes. Micron and Frontier swing hardest by a wide margin, so the color scale is set by the off-diagonal pairs and clips on the diagonal. Those two are also the worst on the left. The assets that move most are the ones the model is being asked to leave out. Off the diagonal, the red cells are the pairs that move against each other, and diversification is built from those.

Solving a model

Each model below has a function of its own. It assembles the model and returns it together with the weight variables, without solving anything. solve takes any one of them, runs Knitro, and turns the weights into a Portfolio. The yield hands a notebook kernel the moment it needs to forward the log Knitro just printed: a sweep that solves without pausing fills the kernel’s output pipe and stops there.

using JuMP
using KNITRO

function solve(market::Market, build; kwargs...)
    model, w = build(market; kwargs...)
    optimize!(model)
    yield()
    weights = value.(w)
    expected = expected_return(market.returns, weights)
    return Portfolio(weights, expected, risk(market.covariance, weights))
end

The Markowitz model

The fundamental model minimizes the risk under a fixed return.

Variables

  • \(w_i \in [0, 1]\), \(i = 1, \dots, N\): proportion of capital invested in asset \(i\)

Objective: minimize the risk

\[ \min \sum_{i=1}^N \sum_{j=1}^N \Sigma_{ij} w_i w_j \]

Constraints

  • Expected return

\[ \sum_{i=1}^N \mu_i w_i \geq R \]

  • Sum of proportions equals 1

\[ \sum_{i=1}^N w_i = 1 \]

The model has the following properties:

  • Continuous variables only
  • Quadratic objective
  • Convex, since a covariance matrix is positive semi-definite
  • Therefore, it is a convex QP

markowitz writes the model above, with the quadratic objective handed to @objective as the double sum it is written with.

function markowitz(market::Market; desired_return)
    mu, sigma = market.returns, market.covariance
    n = num_assets(market)
    model = Model(KNITRO.Optimizer)

    @variable(model, 0 <= w[1:n] <= 1)

    @objective(model, Min, sum(sigma[i, j] * w[i] * w[j] for i in 1:n, j in 1:n))

    @constraint(model, sum(w[i] for i in 1:n) == 1)
    @constraint(model, sum(mu[i] * w[i] for i in 1:n) >= desired_return)

    return model, w
end

Solving for a desired return of 10:

portfolio = solve(nasdaq, markowitz; desired_return=10);
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.087150e+00   6.79e-01
       6    4.289111e-01   1.11e-16   2.13e-08   4.61e-04      0.01

EXIT: Optimal solution found.

HINT: Knitro spent   7.6% of solution time (0.000977 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.28911054277269e-01
Final feasibility error (abs / rel) =   1.11e-16 / 1.93e-18
Final optimality error  (abs / rel) =   2.13e-08 / 1.68e-08
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.01289 (     0.010 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================
Show the full outputHide the full output
draw_portfolio(portfolio, nasdaq.names, "Least risk at a desired return of 10")
@printf("Total risk: %.2f\n", portfolio.risk)
Total risk: 0.43

Here for a desired return of 10, it seems better to diversify to reduce the portfolio risk.

Varying the desired return

In the previous section, we considered a single fixed return. Now let’s consider the optimization for different levels of return.

returns = [5, 7.5, 10, 15]
base = [solve(nasdaq, markowitz; desired_return=r) for r in returns];
Show the full outputHide the full output
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 5e+00] |                [1e+00, 5e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.113473e+00   2.37e-01
       7    3.231341e-01   0.00e+00   2.56e-11   1.59e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  52.6% of solution time (0.001288 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.23134092792703e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   2.56e-11 / 2.56e-11
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00248 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.096865e+00   2.32e-01
       8    3.577912e-01   2.22e-16   6.51e-08   5.03e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  49.0% of solution time (0.001236 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.57791213002902e-01
Final feasibility error (abs / rel) =   2.22e-16 / 4.03e-18
Final optimality error  (abs / rel) =   6.51e-08 / 6.51e-08
# of iterations                     =          8 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00255 (     0.003 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.087150e+00   6.79e-01
       6    4.289111e-01   1.11e-16   2.13e-08   4.61e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  52.5% of solution time (0.001244 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.28911054277269e-01
Final feasibility error (abs / rel) =   1.11e-16 / 1.93e-18
Final optimality error  (abs / rel) =   2.13e-08 / 1.68e-08
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00240 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 2e+01] |                [1e+00, 2e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.101172e+00   3.92e+00
       6    7.666828e-01   0.00e+00   4.52e-11   2.11e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  51.7% of solution time (0.001248 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   7.66682814832761e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   4.52e-11 / 2.14e-11
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00244 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================
draw_comparison(
    base,
    [@sprintf("Return %g, Risk %.2f", r, s.risk) for (r, s) in zip(returns, base)],
    nasdaq.names,
    "Least risk for varying desired returns",
)

Sweeping the desired return over a finer grid traces the efficient frontier: the best risk attainable at each level of return. Every point on it is a solve.

grid = [4 + 0.5 * k for k in 0:22]
frontier = [solve(nasdaq, markowitz; desired_return=r) for r in grid];
Show the full outputHide the full output
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 4e+00] |                [1e+00, 4e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.120086e+00   2.38e-01
       8    3.187773e-01   0.00e+00   3.04e-11   3.89e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  29.8% of solution time (0.000580 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.18777275782998e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   3.04e-11 / 3.04e-11
# of iterations                     =          8 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00197 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 4e+00] |                [1e+00, 4e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.117635e+00   2.38e-01
       7    3.204971e-01   1.11e-16   6.11e-10   5.36e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  12.6% of solution time (0.000261 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.20497086140137e-01
Final feasibility error (abs / rel) =   1.11e-16 / 2.13e-18
Final optimality error  (abs / rel) =   6.11e-10 / 6.11e-10
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00209 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 5e+00] |                [1e+00, 5e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.113473e+00   2.37e-01
       7    3.231341e-01   0.00e+00   2.56e-11   1.59e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  11.9% of solution time (0.000248 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.23134092792703e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   2.56e-11 / 2.56e-11
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00211 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 6e+00] |                [1e+00, 6e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.109591e+00   2.36e-01
       7    3.271836e-01   0.00e+00   7.73e-12   2.51e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  12.3% of solution time (0.000256 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.27183571757067e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   7.73e-12 / 7.73e-12
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00211 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 6e+00] |                [1e+00, 6e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.105989e+00   2.35e-01
       7    3.326742e-01   1.11e-16   1.63e-10   8.08e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  12.1% of solution time (0.000249 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.32674176212433e-01
Final feasibility error (abs / rel) =   1.11e-16 / 2.07e-18
Final optimality error  (abs / rel) =   1.63e-10 / 1.63e-10
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00209 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 6e+00] |                [1e+00, 6e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.102667e+00   2.34e-01
       7    3.396059e-01   0.00e+00   1.06e-09   3.37e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  13.6% of solution time (0.000262 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.39605906702465e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   1.06e-09 / 1.06e-09
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00196 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 7e+00] |                [1e+00, 7e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.099626e+00   2.33e-01
       7    3.479790e-01   0.00e+00   2.58e-07   1.27e-03      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  11.9% of solution time (0.000250 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.47979026747516e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   2.58e-07 / 2.58e-07
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00213 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.096865e+00   2.32e-01
       8    3.577912e-01   2.22e-16   6.51e-08   5.03e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  10.4% of solution time (0.000218 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.57791213002902e-01
Final feasibility error (abs / rel) =   2.22e-16 / 4.03e-18
Final optimality error  (abs / rel) =   6.51e-08 / 6.51e-08
# of iterations                     =          8 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00213 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.094384e+00   2.31e-01
       7    3.689799e-01   2.22e-16   2.18e-08   6.91e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  11.8% of solution time (0.000249 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.68979871227832e-01
Final feasibility error (abs / rel) =   2.22e-16 / 4.00e-18
Final optimality error  (abs / rel) =   2.18e-08 / 2.11e-08
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00213 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.092163e+00   2.30e-01
       7    3.815114e-01   7.79e-11   5.99e-11   1.92e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  12.0% of solution time (0.000251 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.81511437462774e-01
Final feasibility error (abs / rel) =   7.79e-11 / 1.39e-12
Final optimality error  (abs / rel) =   5.99e-11 / 5.54e-11
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00212 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 9e+00] |                [1e+00, 9e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.090213e+00   2.39e-01
       7    3.953859e-01   8.66e-11   7.93e-11   1.86e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  12.7% of solution time (0.000252 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.95385911757145e-01
Final feasibility error (abs / rel) =   8.66e-11 / 1.53e-12
Final optimality error  (abs / rel) =   7.93e-11 / 7.05e-11
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00200 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.088542e+00   4.59e-01
       6    4.108481e-01   0.00e+00   5.35e-07   3.64e-03      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  13.0% of solution time (0.000259 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.10848097034628e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   5.35e-07 / 4.50e-07
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00202 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.087150e+00   6.79e-01
       6    4.289111e-01   1.11e-16   2.13e-08   4.61e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   7.5% of solution time (0.000148 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.28911054277269e-01
Final feasibility error (abs / rel) =   1.11e-16 / 1.93e-18
Final optimality error  (abs / rel) =   2.13e-08 / 1.68e-08
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00200 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.086037e+00   8.99e-01
       6    4.496874e-01   0.00e+00   1.17e-10   7.54e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   9.9% of solution time (0.000196 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.49687421120634e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   1.17e-10 / 8.75e-11
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00201 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.085204e+00   1.12e+00
       6    4.731767e-01   2.22e-16   1.69e-11   1.63e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  13.0% of solution time (0.000257 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.73176703650771e-01
Final feasibility error (abs / rel) =   2.22e-16 / 3.79e-18
Final optimality error  (abs / rel) =   1.69e-11 / 1.19e-11
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00201 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.084650e+00   1.34e+00
       5    4.993811e-01   0.00e+00   1.07e-06   7.43e-03      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  10.1% of solution time (0.000196 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   4.99381056261065e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   1.07e-06 / 7.14e-07
# of iterations                     =          5 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00197 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.084375e+00   1.56e+00
       5    5.282955e-01   1.11e-16   8.20e-07   6.15e-03      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   7.5% of solution time (0.000146 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   5.28295468844518e-01
Final feasibility error (abs / rel) =   1.11e-16 / 1.86e-18
Final optimality error  (abs / rel) =   8.20e-07 / 5.22e-07
# of iterations                     =          5 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00199 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.084380e+00   1.78e+00
       6    5.599220e-01   0.00e+00   2.17e-11   1.10e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   8.4% of solution time (0.000165 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   5.59922033425558e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   2.17e-11 / 1.32e-11
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00199 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.084664e+00   2.00e+00
       6    5.942630e-01   0.00e+00   2.48e-09   1.93e-04      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   7.7% of solution time (0.000154 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   5.94262971067329e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   2.48e-09 / 1.44e-09
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00203 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.088670e+00   2.47e+00
       7    6.313168e-01   8.36e-11   1.27e-11   5.78e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   9.9% of solution time (0.000201 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   6.31316820917614e-01
Final feasibility error (abs / rel) =   8.36e-11 / 1.37e-12
Final optimality error  (abs / rel) =   1.27e-11 / 7.05e-12
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00206 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.092828e+00   2.95e+00
       6    6.713871e-01   0.00e+00   9.09e-08   1.23e-03      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   8.0% of solution time (0.000158 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   6.71387134348436e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   9.09e-08 / 4.80e-08
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00200 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.096995e+00   3.44e+00
       6    7.163964e-01   0.00e+00   3.61e-10   5.63e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent  10.4% of solution time (0.000205 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   7.16396428775274e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   3.61e-10 / 1.80e-10
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00199 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |         2         0         8
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        20           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        20        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 2e+01] |                [1e+00, 2e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.101172e+00   3.92e+00
       6    7.666828e-01   0.00e+00   4.52e-11   2.11e-05      0.00

EXIT: Optimal solution found.

HINT: Knitro spent   7.4% of solution time (0.000147 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   7.66682814832761e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   4.52e-11 / 2.14e-11
# of iterations                     =          6 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00200 (     0.002 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================
draw_frontier(grid, frontier, "Efficient frontier"; highlight=findfirst(==(10.0), grid))

Here we can observe the different assets and their weights based on the desired return. For low returns, it is advantageous to diversify the assets in which to allocate parts of the portfolio, to minimize the risk. On the other hand, as we aim for higher returns, and consequently accept higher risks, we end up investing in the asset that yields the most.

Adding diversification bounds

In portfolio optimization, diversification is a critical principle used to reduce risk by allocating investments among various financial assets, industries, and other categories. Diversification has multiple benefits:

  1. Risk Reduction: Diversification helps in spreading risk across different assets, reducing the impact of any single asset’s poor performance on the overall portfolio.
  2. Control Over Portfolio Composition: By setting bounds on asset weights and limiting the number of assets, investors can ensure that the portfolio remains manageable and aligned with investment objectives.
  3. Improved Returns: A well-diversified portfolio can improve the risk-adjusted returns by taking advantage of the benefits of diversification without excessive exposure to any single asset.

For each asset in the portfolio, we define a lower bound \(L_i\) and an upper bound \(U_i\) on the weight \(w_i\):

\[ \forall i = 1, \dots, N \qquad L_i \leq w_i \leq U_i \]

This constraint ensures that the weight of each asset remains within a specified range, promoting diversification by preventing over-concentration in any single asset. Nothing else changes, so the model is still a convex QP.

with_bounds calls markowitz and adds the two bounds per asset to what comes back.

function with_bounds(market::Market; desired_return, lower, upper)
    model, w = markowitz(market; desired_return=desired_return)

    for i in 1:num_assets(market)
        @constraint(model, w[i] >= lower[i])
        @constraint(model, w[i] <= upper[i])
    end

    return model, w
end

We need to specify additional inputs for this extension. Each asset gets a floor of its own, and all of them share a ceiling of half the capital.

lower = [0.05, 0.05, 0.06, 0.07, 0.06, 0.05, 0.06, 0.07, 0.05, 0.06]
upper = fill(0.5, num_assets(nasdaq))
bounded = [
    solve(nasdaq, with_bounds; desired_return=r, lower=lower, upper=upper) for
    r in returns
];
Show the full outputHide the full output
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
No start point provided -- Knitro computing one.

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

datacheck                0
feastol                  1e-06
feastol_abs              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |        10         0         0
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                   22 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1        21         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        40           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        40        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [5e-02, 7e-02]
  constraint bounds:         [5e-02, 5e+00] |                [1e+00, 5e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    7.716469e-01   5.43e+00
      10    1.005011e+00   1.65e-02   7.85e-03   2.83e-04      0.00
      11    1.005012e+00   1.65e-02   7.85e-03   5.78e-07      0.00

EXIT: Convergence to an infeasible point. The problem is determined
      to be infeasible.

HINT: Knitro spent  12.2% of solution time (0.000306 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   1.00501169801487e+00
Final feasibility error (abs / rel) =   1.65e-02 / 3.13e-04
Final optimality error  (abs / rel) =   7.85e-03 / 2.78e-03
# of iterations                     =         11 
# of CG iterations                  =          4 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00253 (     0.003 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
No start point provided -- Knitro computing one.

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

datacheck                0
feastol                  1e-06
feastol_abs              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |        10         0         0
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                   22 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1        21         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        40           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        40        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [5e-02, 7e-02]
  constraint bounds:         [5e-02, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    7.867780e-01   7.86e+00
      10    1.068222e+00   5.82e-02   2.02e-02   2.34e-05      0.00
      20    1.068314e+00   5.83e-02   2.02e-02   2.28e-03      0.00
      29    1.068286e+00   5.82e-02   2.02e-02   1.50e-07      0.00

EXIT: Convergence to an infeasible point. The problem is determined
      to be infeasible.

HINT: Knitro spent   4.6% of solution time (0.000159 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   1.06828603559199e+00
Final feasibility error (abs / rel) =   5.82e-02 / 1.06e-03
Final optimality error  (abs / rel) =   2.02e-02 / 6.78e-03
# of iterations                     =         29 
# of CG iterations                  =         13 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00345 (     0.003 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
No start point provided -- Knitro computing one.

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

datacheck                0
feastol                  1e-06
feastol_abs              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |        10         0         0
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                   22 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1        21         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        40           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        40        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [5e-02, 7e-02]
  constraint bounds:         [5e-02, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    8.867058e-01   9.23e+00
      10    1.143000e+00   1.00e-01   3.26e-02   4.86e-03      0.00
      18    1.143023e+00   1.00e-01   3.26e-02   1.19e-07      0.00

EXIT: Convergence to an infeasible point. The problem is determined
      to be infeasible.

HINT: Knitro spent   9.1% of solution time (0.000266 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   1.14302250322486e+00
Final feasibility error (abs / rel) =   1.00e-01 / 1.74e-03
Final optimality error  (abs / rel) =   3.26e-02 / 1.04e-02
# of iterations                     =         18 
# of CG iterations                  =          9 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00294 (     0.003 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
No start point provided -- Knitro computing one.

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

datacheck                0
feastol                  1e-06
feastol_abs              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                     10 |                            10
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        10 |        10         0         0
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                   22 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1        21         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        40           |         0        20          
  quadratic:         10         0        55 |        10         0        55
  total:             10        40        55 |        10        20        55
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-01, 7e+01] |                [3e-01, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [5e-02, 7e-02]
  constraint bounds:         [5e-02, 2e+01] |                [1e+00, 2e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    1.270330e+00   9.20e+00
      10    9.724567e+00   1.49e+00   4.22e+00   1.38e+00      0.00
      20    1.326475e+00   1.83e-01   5.75e-02   4.27e-02      0.00
      30    1.326869e+00   1.84e-01   5.74e-02   1.74e-05      0.00
      34    1.326885e+00   1.84e-01   5.74e-02   9.27e-08      0.00

EXIT: Convergence to an infeasible point. The problem is determined
      to be infeasible.

HINT: Knitro spent   5.5% of solution time (0.000211 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   1.32688503054724e+00
Final feasibility error (abs / rel) =   1.84e-01 / 2.93e-03
Final optimality error  (abs / rel) =   5.74e-02 / 1.66e-02
# of iterations                     =         34 
# of CG iterations                  =         18 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00386 (     0.004 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================
draw_comparison(
    bounded,
    [@sprintf("Return %g, Risk %.2f", r, s.risk) for (r, s) in zip(returns, bounded)],
    nasdaq.names,
    "Least risk with every weight bounded",
)

The floors force capital into assets the model had left out, including the ones with a negative expected return, so the same desired return has to be met from a worse starting position. Every portfolio here was already available to the model before and it did not choose one, so bounding the weights can only raise the risk.

Adding a cardinality limit

To further control the diversification, we introduce a cardinality constraint to ensure that exactly \(K\) assets are selected in the portfolio. For this, we introduce a new set of binary variables:

  • \(x_i \in \{0, 1\}\), \(i = 1, \dots, N\): \(x_i = 1\) iff asset \(i\) is selected in the portfolio

The diversification constraints and the linking constraints between \(x_i\) and \(w_i\) merge into a single pair of bounds, alongside the cardinality constraint itself:

\[ \forall i = 1, \dots, N \qquad L_i x_i \leq w_i \leq U_i x_i, \qquad \sum_{i=1}^N x_i = K \]

This ensures that if an asset \(i\) is not selected (\(x_i = 0\)), its weight \(w_i\) will be zero. If an asset is selected (\(x_i = 1\)), its weight will lie between \(L_i\) and \(U_i\).

The binary variables make this a mixed-integer QP, harder than the two models before it.

Every bound here is multiplied by a binary, so with_cardinality builds on markowitz rather than on with_bounds.

function with_cardinality(market::Market; desired_return, lower, upper, cardinality)
    model, w = markowitz(market; desired_return=desired_return)
    n = num_assets(market)

    @variable(model, x[1:n], Bin)
    for i in 1:n
        @constraint(model, w[i] >= lower[i] * x[i])
        @constraint(model, w[i] <= upper[i] * x[i])
    end
    @constraint(model, sum(x[i] for i in 1:n) == cardinality)

    return model, w
end

The same bounds apply here, and exactly three assets may be held.

limited = [
    solve(
        nasdaq,
        with_cardinality;
        desired_return=r,
        lower=lower,
        upper=upper,
        cardinality=3,
    ) for r in returns
];
Show the full outputHide the full output
=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQP
Objective: minimize / quadratic
Number of variables:                     20 |                            20
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        20 |         5         0        15
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     10        10         0 |        10        10         0
Number of constraints:                   23 |                            23
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             2        21         0 |         2        21         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        70           |         0        70          
  quadratic:         10         0        55 |        10         0        55
  total:             10        70        55 |        10        70        55

Knitro using Branch and Bound method with 8 threads.

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:        [5e-02, 7e+01] |                [5e-02, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 5e+00] |                [1e+00, 5e+00]

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0       0.430856          2.59006          0.156436       0.004
    1       0.430856          2.59006          0.156436       0.004
    2       0.503552      4.44089e-16          0.182691       0.004
    3       0.417456      4.44089e-16       2.07379e-02       0.005
    4       0.347627      8.88178e-16       3.10890e-03       0.005
    5       0.328335      2.22045e-16       5.61765e-04       0.005
    6       0.323952      8.88178e-16       7.84677e-05       0.005
    7       0.323144      4.44089e-16       2.05361e-06       0.005
    8       0.323134      7.80792e-12       1.78962e-10       0.005
    9       0.323134      7.80792e-12       1.78962e-10       0.005
   10       0.323134      4.44089e-16       2.43939e-08       0.006

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       2     0.505370   LS     0.323134     18.22%     0.007
      3       4     0.479976   LS     0.323134     15.68%     0.023
     10      11     0.391153 MPEC     0.329103      6.20%     0.042
     27       0     0.391153          0.391114      0.00%     0.058

EXIT: Optimal solution found.

HINT: Knitro spent   3.0% of solution time (0.002310 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  3.91152827306554263e-01
Final bound value                   =  3.91113712023823612e-01
Final optimality gap (abs / rel)    =  3.91153e-05 / 3.91153e-05 (0.00%)
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  27 (0.048s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  32 (0.058s)
Total program time (secs)           =  0.07637 (0.172 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 1 / 0.013s
Rounding heuristic                  =  1 / 0 / 0.000s
MPEC heuristic                      =  1 / 1 / 0.004s
Local search heuristic              =  8 / 5 / 0.030s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQP
Objective: minimize / quadratic
Number of variables:                     20 |                            20
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        20 |         5         0        15
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     10        10         0 |        10        10         0
Number of constraints:                   23 |                            23
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             2        21         0 |         2        21         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        70           |         0        70          
  quadratic:         10         0        55 |        10         0        55
  total:             10        70        55 |        10        70        55

Knitro using Branch and Bound method with 8 threads.

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:        [5e-02, 7e+01] |                [5e-02, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0       0.401827          3.61497          0.157052       0.001
    1       0.401827          3.61497          0.157052       0.001
    2       0.496356      8.51961e-03          0.187828       0.001
    3       0.477358      1.45431e-04       2.25667e-02       0.001
    4       0.376725      4.44089e-16       8.12537e-03       0.002
    5       0.361378      4.44089e-16       4.98045e-04       0.002
    6       0.357859      4.44089e-16       6.43383e-05       0.002
    7       0.357795      8.88178e-16       3.68238e-06       0.002
    8       0.357791      4.44089e-16       2.80556e-07       0.002
    9       0.357791      4.44089e-16       2.80556e-07       0.002
   10       0.357791      4.44089e-16       8.57410e-07       0.002

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       2     0.506866 FCRD     0.357791     14.91%     0.019
     31       0     0.506866          0.506816      0.01%     0.049

EXIT: Optimal solution found.

Final Statistics for MIP
------------------------
Final objective value               =  5.06866190634101987e-01
Final bound value                   =  5.06815504015038609e-01
Final optimality gap (abs / rel)    =  5.06866e-05 / 5.06866e-05 (0.01%)
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  31 (0.047s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  34 (0.057s)
Total program time (secs)           =  0.04921 (0.080 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.001s
Rounding heuristic                  =  1 / 1 / 0.006s
MPEC heuristic                      =  1 / 0 / 0.003s
Local search heuristic              =  7 / 3 / 0.033s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQP
Objective: minimize / quadratic
Number of variables:                     20 |                            20
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        20 |         5         0        15
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     10        10         0 |        10        10         0
Number of constraints:                   23 |                            23
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             2        21         0 |         2        21         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        70           |         0        70          
  quadratic:         10         0        55 |        10         0        55
  total:             10        70        55 |        10        70        55

Knitro using Branch and Bound method with 8 threads.

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:        [5e-02, 7e+01] |                [5e-02, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0       0.405243          3.56028          0.157915       0.001
    1       0.405243          3.56028          0.157915       0.001
    2       0.499915      2.14435e-02          0.186931       0.002
    3       0.576766      0.00000e+00       2.17350e-02       0.002
    4       0.476514      4.44089e-16       4.88309e-03       0.002
    5       0.433684      4.44089e-16       6.66356e-04       0.002
    6       0.429045      8.88178e-16       6.22491e-05       0.002
    7       0.428911      2.22045e-16       4.11592e-08       0.002
    8       0.428911      6.57219e-11       3.42538e-08       0.002
    9       0.428911      2.22045e-16       1.83348e-08       0.003

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       2     0.891125   LS     0.428911     46.22%     0.004
      2       3     0.723167   LS     0.428911     29.43%     0.006
      9      10     0.511145 MPEC     0.428911      8.22%     0.014
     21       0     0.511145          0.511093      0.01%     0.018

EXIT: Optimal solution found.

HINT: Knitro spent   1.0% of solution time (0.000187 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  5.11144529489658161e-01
Final bound value                   =  5.11093415036709242e-01
Final optimality gap (abs / rel)    =  5.11145e-05 / 5.11145e-05 (0.01%)
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  21 (0.030s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  24 (0.038s)
Total program time (secs)           =  0.01853 (0.066 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 1 / 0.004s
Rounding heuristic                  =  2 / 1 / 0.003s
MPEC heuristic                      =  1 / 1 / 0.003s
Local search heuristic              =  8 / 3 / 0.017s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQP
Objective: minimize / quadratic
Number of variables:                     20 |                            20
  bounds:         lower     upper     range |     lower     upper     range
                      0         0        20 |         5         0        15
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     10        10         0 |        10        10         0
Number of constraints:                   23 |                            23
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             2        21         0 |         2        21         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0        70           |         0        70          
  quadratic:         10         0        55 |        10         0        55
  total:             10        70        55 |        10        70        55

Knitro using Branch and Bound method with 8 threads.

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:        [5e-02, 7e+01] |                [5e-02, 7e+01]
  quadratic objective:       [2e-02, 1e+01] |                [2e-02, 1e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 2e+01] |                [1e+00, 2e+01]

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0       0.422045          8.42097          0.158771       0.002
    1       0.422045          8.42097          0.158771       0.002
    2       0.536720      4.94265e-02          0.201772       0.002
    3       0.889723      4.89048e-03          0.142338       0.002
    4       0.836220      0.00000e+00       9.98626e-03       0.002
    5       0.780900      4.44089e-16       1.83991e-03       0.002
    6       0.766963      4.44089e-16       2.00489e-04       0.002
    7       0.766683      0.00000e+00       1.82529e-08       0.002
    8       0.766683      8.42165e-11       1.54466e-08       0.003
    9       0.766683      1.52462e-24       3.40515e-09       0.003

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       2                       0.766683                0.004
      7       8     0.843554 FCRD     0.775295      6.83%     0.011
     15       0     0.843554          0.843470      0.01%     0.015

EXIT: Optimal solution found.

HINT: Knitro spent   1.3% of solution time (0.000204 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  8.43554338298756701e-01
Final bound value                   =  8.43469982864926804e-01
Final optimality gap (abs / rel)    =  8.43554e-05 / 8.43554e-05 (0.01%)
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  15 (0.018s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  17 (0.027s)
Total program time (secs)           =  0.01545 (0.044 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 1 / 0.005s
Rounding heuristic                  =  2 / 1 / 0.003s
MPEC heuristic                      =  1 / 1 / 0.003s
Local search heuristic              =  6 / 0 / 0.008s

===========================================================================
draw_comparison(
    limited,
    [@sprintf("Return %g, Risk %.2f", r, s.risk) for (r, s) in zip(returns, limited)],
    nasdaq.names,
    "Least risk holding exactly three assets",
)

By incorporating extensions related to diversification and cardinality constraints, some assets may no longer be included in the portfolio, while others may see their weights increase. This occurs because such constraints can limit the number of assets selected and enforce a more concentrated allocation, thereby intensifying the focus on a smaller set of high-performing assets.

The risks come out below the ones in the figure above. That looks wrong for a model carrying an extra constraint. The reason is that a floor now reads \(L_i x_i\), so it applies only to an asset that is actually held, and the seven that are dropped stop having to be paid for.

Rebalancing with transaction costs

Rebalancing a portfolio involves buying and selling securities to adjust its composition, leading to turnover. While the basic Markowitz model assumes there are no trading costs, in practice, turnover incurs expenses. There are two kinds of transaction costs:

  • Fixed costs, which represent commissions or transfer fees
  • Variable costs, which depend on the transaction volume, representing costs such as market impact or bid/ask spread

In the variant considered in this section, the objective is to maximize the return and the maximum risk is set as a constraint. To make the model more meaningful, we consider that a proportion of the capital is already invested in some assets.

Input

  • \(W^0_i\): fraction of the portfolio value already invested in asset \(i\)
  • \(\Gamma\): limited risk level
  • \(F_i\): fixed cost if buying asset \(i\)
  • \(V_i\): variable factor cost when buying asset \(i\)

Variables. We need two additional sets of variables to model the absolute value \(|w_i - W^0_i|\), the proportion of the capital moved from asset \(i\) (bought or sold):

  • \(z^+_i \in [0, 1]\): positive part of \(w_i - W^0_i\)
  • \(z^-_i \in [0, 1]\): negative part of \(w_i - W^0_i\)

Objective: maximize the return

\[ \max \sum_{i=1}^N \mu_i w_i \]

Constraints

\[ z^+_i - z^-_i = w_i - W^0_i, \qquad \sum_{i=1}^N \sum_{j=1}^N \Sigma_{ij} w_i w_j \leq \Gamma, \qquad \sum_{i=1}^N w_i + \sum_{i=1}^N \big( F_i x_i + V_i (z^+_i + z^-_i) \big) = \sum_{i=1}^N W^0_i \]

rebalance keeps nothing from markowitz. The objective and the risk have swapped places.

function rebalance(market::Market; holdings, max_risk, fixed_cost, variable_cost)
    mu, sigma = market.returns, market.covariance
    n = num_assets(market)
    model = Model(KNITRO.Optimizer)

    @variable(model, 0 <= w[1:n] <= 1)
    @variable(model, x[1:n], Bin)
    @variable(model, z_plus[1:n] >= 0)
    @variable(model, z_minus[1:n] >= 0)

    @objective(model, Max, sum(mu[i] * w[i] for i in 1:n))

    for i in 1:n
        @constraint(model, z_plus[i] - z_minus[i] == w[i] - holdings[i])
    end

    variance = @expression(model, sum(sigma[i, j] * w[i] * w[j] for i in 1:n, j in 1:n))
    @constraint(model, variance <= max_risk)

    @constraint(
        model,
        sum(w[i] for i in 1:n) + sum(
            fixed_cost[i] * x[i] + variable_cost[i] * (z_plus[i] + z_minus[i]) for
            i in 1:n
        ) == sum(holdings)
    )

    return model, w
end

A high variable cost limits the changes we can make to our current portfolio. That’s why it’s important to vary this factor to observe the differences. We start from an equally weighted portfolio.

gamma = 0.7
w0 = fill(1 / num_assets(nasdaq), num_assets(nasdaq))
fixed_cost = fill(0.1, num_assets(nasdaq))
variable_costs = [1, 0.75, 0.5, 0.25, 0]

initial_return = expected_return(nasdaq.returns, w0)
initial = Portfolio(w0, initial_return, risk(nasdaq.covariance, w0))
rebalanced = [
    solve(
        nasdaq,
        rebalance;
        holdings=w0,
        max_risk=gamma,
        fixed_cost=fixed_cost,
        variable_cost=fill(v, num_assets(nasdaq)),
    ) for v in variable_costs
];
Show the full outputHide the full output
=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQCQP
Objective: maximize / linear   
Number of variables:                     40 |                            40
  bounds:         lower     upper     range |     lower     upper     range
                     20         0        20 |        20         0        20
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     30        10         0 |        30        10         0
Number of constraints:                   12 |                            12
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            11         0         0 |        11         0         0
  quadratic:          0         1         0 |         0         1         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10        70           |        10        70          
  quadratic:          0        10        55 |         0        10        55
  total:             10        80        55 |        10        80        55

Knitro using Branch and Bound method with 8 threads.

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

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

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0        3.62551         0.481231           22.5372       0.004
    1        5.66721         0.458116           1.27690       0.005
    2        6.16459         0.175048          0.681292       0.005
    3        5.74630      1.26574e-02          0.106390       0.005
    4        6.61044      1.96393e-04       9.68422e-03       0.005
    5        6.65243      1.42437e-06       8.59905e-05       0.006
    6        6.65278      1.36152e-10       8.22768e-09       0.006
    7        6.65278      1.22125e-15       3.27769e-15       0.006
    8        6.65278      1.22125e-15       3.27769e-15       0.007

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       0      6.65278 LEAF      6.65278      0.00%     0.008

EXIT: Optimal solution found.

HINT: Knitro spent  18.3% of solution time (0.001574 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  6.65278400000000047e+00
Final bound value                   =  6.65278400000000047e+00
Final optimality gap (abs / rel)    =  0.00000e+00 / 0.00000e+00 (0.00%)
# of root cutting plane rounds      =  0
# of restarts                       =  0
# of nodes processed                =  1 (0.004s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  1 (0.004s)
Total program time (secs)           =  0.00857 (0.031 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  0 / 0 / 0.000s
Rounding heuristic                  =  0 / 0 / 0.000s
MPEC heuristic                      =  0 / 0 / 0.000s
Local search heuristic              =  3 / 2 / 0.010s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQCQP
Objective: maximize / linear   
Number of variables:                     40 |                            40
  bounds:         lower     upper     range |     lower     upper     range
                     20         0        20 |        20         0        20
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     30        10         0 |        30        10         0
Number of constraints:                   12 |                            12
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            11         0         0 |        11         0         0
  quadratic:          0         1         0 |         0         1         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10        70           |        10        70          
  quadratic:          0        10        55 |         0        10        55
  total:             10        80        55 |        10        80        55

Knitro using Branch and Bound method with 8 threads.

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

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

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0        1.49121         0.459886           22.9065       0.002
    1        4.53486         0.424316          0.630298       0.002
    2        4.76318      5.82386e-02          0.237583       0.002
    3        7.97230      3.05881e-03       7.36196e-02       0.002
    4        8.11599      1.54270e-05       4.46135e-04       0.002
    5        8.11679      6.86051e-09       2.05212e-07       0.002
    6        8.11679      9.99201e-16       7.25091e-14       0.003
    7        8.11679      3.33067e-16       1.77636e-15       0.003

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       0      8.11679 LEAF      8.11679      0.00%     0.005

EXIT: Optimal solution found.

HINT: Knitro spent   6.5% of solution time (0.000312 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  8.11679471428571730e+00
Final bound value                   =  8.11679471428571730e+00
Final optimality gap (abs / rel)    =  0.00000e+00 / 0.00000e+00 (0.00%)
# of root cutting plane rounds      =  0
# of restarts                       =  0
# of nodes processed                =  1 (0.002s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  1 (0.002s)
Total program time (secs)           =  0.00480 (0.019 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  0 / 0 / 0.000s
Rounding heuristic                  =  0 / 0 / 0.000s
MPEC heuristic                      =  0 / 0 / 0.000s
Local search heuristic              =  4 / 0 / 0.007s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQCQP
Objective: maximize / linear   
Number of variables:                     40 |                            40
  bounds:         lower     upper     range |     lower     upper     range
                     20         0        20 |        20         0        20
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     30        10         0 |        30        10         0
Number of constraints:                   12 |                            12
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            11         0         0 |        11         0         0
  quadratic:          0         1         0 |         0         1         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10        70           |        10        70          
  quadratic:          0        10        55 |         0        10        55
  total:             10        80        55 |        10        80        55

Knitro using Branch and Bound method with 8 threads.

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

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

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0   -7.62974e-03         0.311630           20.7306       0.003
    1       0.687604         0.265939           3.32889       0.003
    2        7.25574      5.04446e-03          0.489625       0.004
    3        9.61621      1.34356e-05       8.85160e-02       0.004
    4        10.0644      7.03796e-08       4.76010e-03       0.004
    5        10.0688      3.34970e-10       2.27094e-05       0.004
    6        10.0688      4.69624e-14       9.82956e-10       0.004
    7        10.0688      5.55112e-16       1.77636e-15       0.004

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       0      10.0688 LEAF      10.0688      0.00%     0.005

EXIT: Optimal solution found.

HINT: Knitro spent   6.9% of solution time (0.000337 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  1.00688090000000052e+01
Final bound value                   =  1.00688090000000052e+01
Final optimality gap (abs / rel)    =  0.00000e+00 / 0.00000e+00 (0.00%)
# of root cutting plane rounds      =  0
# of restarts                       =  0
# of nodes processed                =  1 (0.004s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  1 (0.004s)
Total program time (secs)           =  0.00491 (0.019 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  0 / 0 / 0.000s
Rounding heuristic                  =  0 / 0 / 0.000s
MPEC heuristic                      =  0 / 0 / 0.000s
Local search heuristic              =  3 / 0 / 0.003s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQCQP
Objective: maximize / linear   
Number of variables:                     40 |                            40
  bounds:         lower     upper     range |     lower     upper     range
                     20         0        20 |        20         0        20
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     30        10         0 |        30        10         0
Number of constraints:                   12 |                            12
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            11         0         0 |        11         0         0
  quadratic:          0         1         0 |         0         1         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10        70           |        10        70          
  quadratic:          0        10        55 |         0        10        55
  total:             10        80        55 |        10        80        55

Knitro using Branch and Bound method with 8 threads.

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

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

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0   -7.62974e-03         0.319289           17.7501       0.002
    1        6.95074         0.270550          0.503348       0.002
    2        4.23543      4.59978e-03          0.460908       0.002
    3        8.87075      4.44089e-16          0.202509       0.002
    4        12.4708      5.55112e-16       9.57692e-02       0.003
    5        13.0077      2.22045e-16          0.175908       0.003
    6        13.3561      1.52356e-03       7.64986e-03       0.003
    7        13.3721      1.10720e-05       7.59572e-05       0.003
    8        13.3722      8.17621e-10       5.83764e-09       0.003
    9        13.3722      1.00001e-10       1.00001e-10       0.003
   10        13.3722      7.77156e-16       3.30518e-11       0.003

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       0      13.3722 LEAF      13.3722      0.00%     0.006

EXIT: Optimal solution found.

HINT: Knitro spent   5.5% of solution time (0.000363 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics for MIP
------------------------
Final objective value               =  1.33721742807601345e+01
Final bound value                   =  1.33721742807601345e+01
Final optimality gap (abs / rel)    =  0.00000e+00 / 0.00000e+00 (0.00%)
# of root cutting plane rounds      =  0
# of restarts                       =  0
# of nodes processed                =  1 (0.003s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  1 (0.003s)
Total program time (secs)           =  0.00655 (0.018 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  0 / 0 / 0.000s
Rounding heuristic                  =  0 / 0 / 0.000s
MPEC heuristic                      =  0 / 0 / 0.000s
Local search heuristic              =  4 / 0 / 0.006s

===========================================================================


=======================================
          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
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 1.
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.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex MIQCQP
Objective: maximize / linear   
Number of variables:                     40 |                            40
  bounds:         lower     upper     range |     lower     upper     range
                     20         0        20 |        20         0        20
                             free     fixed |                free     fixed
                                0         0 |                   0         0
                  cont.    binary   integer |     cont.    binary   integer
                     30        10         0 |        30        10         0
Number of constraints:                   12 |                            12
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:            11         0         0 |        11         0         0
  quadratic:          0         1         0 |         0         1         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:            10        50           |        10        50          
  quadratic:          0        10        55 |         0        10        55
  total:             10        60        55 |        10        60        55

Knitro using Branch and Bound method with 8 threads.

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

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

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

 Iter      Objective      Feasibility        Optimality       Time 
                             error              error        (secs)
 ----      ---------      -----------        ----------      ------
    0       -2.14993         0.247679           2.47881       0.001
    1        16.4376         0.498363          0.419039       0.002
    2        16.7830         0.524616          0.497705       0.002
    3        14.4156      4.52455e-02          0.535123       0.002
    4        14.2755      2.13718e-15          0.614291       0.002
    5        14.3339      4.70571e-05       2.91922e-02       0.002
    6        14.3374      1.71096e-05       4.09953e-03       0.002
    7        14.3373      6.00300e-08       2.65597e-05       0.003
    8        14.3373      1.04091e-10       1.22909e-09       0.003
    9        14.3373      5.97291e-11       5.35892e-06       0.003

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

       Nodes        Best solution   Best bound      Gap       Time 
   Expl  |  Unexpl      value         value                  (secs)
   ---------------  -------------   ----------      ---      ------
      1       2      14.3245 FCRD      14.3373      0.09%     0.008
      7       2      14.3245 MPEC      14.3373      0.09%     0.017
     21       0      14.3245           14.3260      0.01%     0.046

EXIT: Optimal solution found.

Final Statistics for MIP
------------------------
Final objective value               =  1.43245316811231227e+01
Final bound value                   =  1.43259641331530609e+01
Final optimality gap (abs / rel)    =  1.43245e-03 / 9.99999e-05 (0.01%)
# of root cutting plane rounds      =  1
# of restarts                       =  0
# of nodes processed                =  21 (0.037s)
# of strong branching evaluations   =  0 (0.000s)
# of function evaluations           =  0 (0.000s)
# of gradient evaluations           =  0 (0.000s)
# of hessian evaluations            =  0 (0.000s)
# of hessian-vector evaluations     =  0
# of subproblems processed          =  28 (0.051s)
Total program time (secs)           =  0.04599 (0.136 CPU time)
Time spent in evaluations (secs)    =  0.00000

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

Heuristics statistics (calls / successes / time)
------------------------------------------------
Feasibility pump                    =  1 / 0 / 0.002s
Rounding heuristic                  =  1 / 1 / 0.003s
MPEC heuristic                      =  1 / 1 / 0.003s
Local search heuristic              =  7 / 4 / 0.025s

===========================================================================
draw_comparison(
    [initial; rebalanced],
    [
        @sprintf("Initial, Return %.2f", initial.expected_return)
        [
            @sprintf("Variable cost %g, Return %.2f", v, s.expected_return) for
            (v, s) in zip(variable_costs, rebalanced)
        ]
    ],
    nasdaq.names,
    "Rebalancing an equally weighted portfolio",
)

When transaction costs are taken into account, assets with negative expected returns are removed from the portfolio, because the costs associated with trading prevent extensive diversification, making it impractical to include assets that do not contribute positively to the portfolio’s overall return. The lower the variable cost, the further the portfolio can move from its initial allocation.

Optimizing portfolios with a large number of assets

In this section, we test the baseline model with a large number of assets. Despite the increased complexity, we expect to solve the optimization problem successfully using Knitro. The data is taken from the top 100 companies listed on the Australian Securities Exchange (ASX).

asx = load_market("asx.csv", "Top 100 of the Australian Securities Exchange")

large_returns = [5.0, 7.5, 10.0, 15.0]
large = [solve(asx, markowitz; desired_return=r) for r in large_returns];
Show the full outputHide the full output
=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                    100 |                           100
  bounds:         lower     upper     range |     lower     upper     range
                      0         0       100 |         0         0       100
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0       200           |         0       200          
  quadratic:        100         0      5050 |       100         0      5050
  total:            100       200      5050 |       100       200      5050
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-02, 2e+01] |                [3e-02, 2e+01]
  quadratic objective:       [8e-04, 2e+01] |                [8e-04, 2e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 5e+00] |                [1e+00, 5e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    3.247304e+00   3.37e+00
      10    2.108031e-01   4.44e-16   5.25e-07   2.31e-03      0.01

EXIT: Optimal solution found.

HINT: Knitro spent   5.8% of solution time (0.000596 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   2.10803066843171e-01
Final feasibility error (abs / rel) =   4.44e-16 / 9.64e-18
Final optimality error  (abs / rel) =   5.25e-07 / 4.10e-07
# of iterations                     =         10 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.01024 (     0.010 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                    100 |                           100
  bounds:         lower     upper     range |     lower     upper     range
                      0         0       100 |         0         0       100
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0       200           |         0       200          
  quadratic:        100         0      5050 |       100         0      5050
  total:            100       200      5050 |       100       200      5050
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-02, 2e+01] |                [3e-02, 2e+01]
  quadratic objective:       [8e-04, 2e+01] |                [8e-04, 2e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 8e+00] |                [1e+00, 8e+00]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    3.501597e+00   4.85e+00
      10    2.412573e-01   2.22e-16   1.58e-06   1.35e-03      0.01
      11    2.412571e-01   0.00e+00   1.45e-10   1.21e-04      0.01

EXIT: Optimal solution found.

HINT: Knitro spent   6.0% of solution time (0.000595 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   2.41257143933544e-01
Final feasibility error (abs / rel) =   0.00e+00 / 0.00e+00
Final optimality error  (abs / rel) =   1.45e-10 / 1.27e-10
# of iterations                     =         11 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00996 (     0.010 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                    100 |                           100
  bounds:         lower     upper     range |     lower     upper     range
                      0         0       100 |         0         0       100
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0       200           |         0       200          
  quadratic:        100         0      5050 |       100         0      5050
  total:            100       200      5050 |       100       200      5050
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-02, 2e+01] |                [3e-02, 2e+01]
  quadratic objective:       [8e-04, 2e+01] |                [8e-04, 2e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 1e+01] |                [1e+00, 1e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    2.653082e+00   5.37e+00
       9    3.220800e-01   6.66e-16   1.10e-07   9.30e-04      0.01

EXIT: Optimal solution found.

HINT: Knitro spent  14.1% of solution time (0.001337 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   3.22080025315401e-01
Final feasibility error (abs / rel) =   6.66e-16 / 1.45e-17
Final optimality error  (abs / rel) =   1.10e-07 / 9.24e-08
# of iterations                     =          9 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00950 (     0.010 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================


=======================================
          Commercial License
         Artelys Knitro 16.0.0
=======================================

Knitro using 1 thread.
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              0.001
hessian_no_f             1
opttol                   1e-06
opttol_abs               0.001
Knitro running advanced initialization strategy specified by initpt_strategy.

Problem Characteristics                     |           Presolved
-----------------------
Problem type: convex QP
Objective: minimize / quadratic
Number of variables:                    100 |                           100
  bounds:         lower     upper     range |     lower     upper     range
                      0         0       100 |         0         0       100
                             free     fixed |                free     fixed
                                0         0 |                   0         0
Number of constraints:                    2 |                             2
                    eq.     ineq.     range |       eq.     ineq.     range
  linear:             1         1         0 |         1         1         0
  quadratic:          0         0         0 |         0         0         0
Number of nonzeros:
              objective  Jacobian   Hessian | objective  Jacobian   Hessian
  linear:             0       200           |         0       200          
  quadratic:        100         0      5050 |       100         0      5050
  total:            100       200      5050 |       100       200      5050
Coefficient range:
  linear objective:          [0e+00, 0e+00] |                [0e+00, 0e+00]
  linear constraints:        [3e-02, 2e+01] |                [3e-02, 2e+01]
  quadratic objective:       [8e-04, 2e+01] |                [8e-04, 2e+01]
  quadratic constraints:     [0e+00, 0e+00] |                [0e+00, 0e+00]
  variable bounds:           [1e+00, 1e+00] |                [1e+00, 1e+00]
  constraint bounds:         [1e+00, 2e+01] |                [1e+00, 2e+01]

Knitro using the Interior-Point/Barrier Direct algorithm.

    Iter       Objective  FeasError   OptError   ||Step||      Time 
--------  --------------  ---------  ---------  ---------  --------
       0    2.367075e+00   5.36e+00
       7    7.590161e-01   4.44e-16   5.27e-11   3.16e-05      0.01

EXIT: Optimal solution found.

HINT: Knitro spent  16.7% of solution time (0.001433 secs) checking model
      convexity. To skip the automatic convexity checker for QPs and QCQPs,
      explicity set the user option convex=0 or convex=1.

Final Statistics
----------------
Final objective value               =   7.59016080822773e-01
Final feasibility error (abs / rel) =   4.44e-16 / 9.48e-18
Final optimality error  (abs / rel) =   5.27e-11 / 2.36e-11
# of iterations                     =          7 
# of CG iterations                  =          0 
# of function evaluations           =          0
# of gradient evaluations           =          0
# of Hessian evaluations            =          0
Total program time (secs)           =       0.00864 (     0.009 CPU time)
Time spent in evaluations (secs)    =       0.00000

================================================================================
draw_comparison(
    large,
    [
        @sprintf("Return %g, Risk %.2f", r, s.risk) for
        (r, s) in zip(large_returns, large)
    ],
    asx.names,
    "Selected assets among the 100 available";
    threshold=0.05,
)

As the figure shows, only a handful of assets are selected to minimize the risk for these desired returns, and the convex QP is still solved to global optimality.

 

Solved with Artelys Knitro · artelys.com