Portfolio Optimization: Factor Model#

portfolio_factor_model.ipynb Open In Colab Open In Deepnote Open In Kaggle Open In Gradient Open In SageMaker Studio Lab Powered by AMPL

Description: Mean-Variance Portfolio Optimization model where the risk estimator is not given explicitly but is instead represented by a factor model, as is common in US equity models [1]. The original notebook is [3].

Tags: finance, portfolio optimization, mean variance, factor model, AMPL conditonal instantiation, cardinality constraint

Notebook author: Gleb Belov <gleb@ampl.com>

References:

[1] Menchero, J., Orr, D., Wang, J.: The Barra US equity model (USE4), methodology notes. English, MSCI. May 2011.

[2] Gérard Cornuéjols, Javier Peña, and Reha Tütüncü. Optimization Methods in Finance. Cambridge University Press, 2 edition, 2018. doi:10.1017/9781107297340.

[3] Gurobi. Factor Model as Objective. https://gurobi-finance.readthedocs.io/en/latest/modeling_notebooks/factor_models_objective.html, accessed Nov 3, 2025.

[4] Mosek ApS. Ferrari, factorizing, and portfolios in conic form. https://themosekblog.blogspot.com/2024/03/ferrari-factorizing-and-portfolios-in.html, accessed Nov 4, 2025.

# Install dependencies
%pip install -q amplpy pandas numpy matplotlib
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["gurobi", "mosek", "highs"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics
# Import extras
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Background#

The standard mean-variance (Markowitz) portfolio selection model determines optimal investments that balance risk and expected return. In this notebook, we maximize utility, which is defined as a weighted linear function of return and risk that can be adjusted by varying the risk-aversion coefficient \(\gamma\).

The standard formulation of this problem on \(n\) assets reads

\[\begin{alignat*}{2} \tag{1} \max_{x \in \mathbf{R}^{n}} \quad & \mu^\top x - \tfrac12 \gamma\ x^\top\Sigma x \\ \mbox{s.t.} \quad & 1_n^\top x = 1 \\ & 0 \le x \le 1\\ \end{alignat*}\]

where \(\mu \in \mathbf{R}^n\) is the return estimator, \(\Sigma \in \mathbf{R}^{n,n}\) is used as an estimator for the variance, and \(1_n\) is the vector of \(n\) ones. While it is certainly possible that the matrix \(\Sigma\) is given explicitly (e.g., as the covariance matrix of a time series), it is often expressed implicitly through a factor model. In that case, the matrix \(\Sigma\) takes the form

\[ \Sigma = X \Sigma_0 X^T + D \]

where

  • \(X \in \mathbf{R}^{n,k}\) is the factor exposure matrix,

  • \(\Sigma_0 \in \mathbf{R}^{k,k}\) is the symmetric positive definite (SPD) factor covariance matrix, and

  • \(D \in \mathbf{R}^{n,n}\) is the diagonal matrix of specific risks with \(d_{ii} > 0\) for all \(i\).

Effectively, this splits the risk into two sources: One that arises from common risk factors (macroeconomic conditions, market trends, etc.) and a specific risk that is uncorrelated among the assets. The number of factors, \(k\), is typically much smaller than the number \(n\) of assets.

The important observation from a computational point of view is the following: The factor model data is of size \(nk + n\) (with \(k \ll n\)), while the covariance matrix \(\Sigma\) is on the order of \(n^2\). As we will see, optimization models using the factor model admit a smaller representation and typically offer improved computational performance.

A synthetic factor model#

Leading industry factor models are commercial products that are not necessary for our demonstration purposes. We are more interested in a qualitative comparison of solver performance using some factor model than in the actual economic meaning. For this reason, our first step will be to create a simple, synthetic multivariate factor model that we can use in the study that follows.

The following function uses an uncorrelated factor covariance matrix \(\Sigma_0\) that is used for sampling a multivariate normal distribution on num_factors factors along time_steps sampling points for num_assets assets:

def factor_model(num_assets, num_factors, timesteps):
    # Generate random factor model, risk is X * sigma0 * X.T + cov(u)
    sigma0 = np.diag(1 + np.arange(num_factors) + np.random.rand(num_factors))
    X = np.random.normal(size=(num_assets, num_factors))
    alpha = np.random.normal(loc=1, size=(num_assets, 1))
    u = np.random.multivariate_normal(
        np.zeros(num_assets), np.eye(num_assets), timesteps
    ).T
    d = np.diag(np.cov(u))  # NOTE: This is the _diagonal_ of D!

    # Time series in factor space
    TS_factor = np.random.multivariate_normal(
        np.zeros(num_factors), sigma0, timesteps
    ).T

    # Estimate mu from time series in full space
    mu = np.mean(alpha + X @ TS_factor + u, axis=1)

    return X, sigma0, d, mu

We skip the details of this statistical procedure for constructing \(X\), \(\Sigma_0\), \(D\), and \(\mu\); more background and details can be found in [2, Sect. 6.6]. The essential point is that we now have a synthetic factor model that acts similarly to a commercial factor model regarding solver performance.

Taking advantage of the factor model structure#

Ignoring the constant factor \(\frac{1}{2}\gamma\) for a moment, the objective function we want to maximize includes

\[ x^T \Sigma x = x^T (X \Sigma_0 X + D) x = x^T X \Sigma_0 X^T x + x^T D x \]

The first term, \(x^T X \Sigma_0 X^T x\), would result in a quadratic function having \((n+1)\frac n2\) terms. Since \(\Sigma_0\) is SPD, it admits a Cholesky factorization \(\Sigma_0 = LL^T\) where \(L \in \mathbf{R}^{k,k}\) is a triangular matrix. This allows us to rewrite the first term as

\[ x^T X \Sigma_0 X^T x = x^T \underbrace{X L}_{B} \underbrace{L^T X^T}_{B^T} x = \underbrace{x^T B}_{y^T} \underbrace{B^T x}_{y} = y^T y \]

where we have substituted \(y = B^T x\) in the last step. Also, note that \(B = X L \in \mathbf{R}^{n, k}\) comprises only \(nk\) elements.

The second term, \(x^T D x\), comprises only \(n\) terms (i.e., \(\sum_i d_{ii} x_{i}^2\)) and can be used as is. Putting this together, the standard optimization model (1) can be rewritten as

(1)#\[\begin{alignat}{2} \tag{2} \max_{x \in \mathbf{R}^{n}, y \in \mathbf{R}^k} \quad & \mu^\top x - \tfrac12 \gamma\ y^T y + \tfrac12 \gamma\ \sum_{i=1}^n d_{ii} x_i^2\\ \mbox{s.t.} \quad & 1_n^\top x = 1 \\ & y = B^T x.\\ & 0 \le x \le 1 \end{alignat}\]

Note that the \(k\) variables \(y\) do not have bound constraints. Model (2) contains the much smaller matrix \(B\) instead of \(\Sigma\) in model (1), at the expense of \(k\) additional optimization variables. Generally, form (2) is advantageous for solver performance; we shall compare both in the next step.

Comparing the two optimization models#

In order to compare the solution times for models (1) and (2) above, we will define an AMPL model translating into either (1) or (2) depending on parameter want_factor_model.

Use %%writefile to save AMPL model (see AMPLPY Best Practices)#

%%writefile portfolio_sigma_factors.mod
set ASSETS;
set FACTORS default {};

# Parameters
param want_factor_model default 1;     # Model (1) or (2)
param expected_return {ASSETS};
param risk_free_rate;                  # gamma
# The below parameters are needed depending on want_factor_model
param factor_loadings {ASSETS, FACTORS};
param asset_specific_risks {ASSETS};
param asset_cov {ASSETS, ASSETS};   # The full matrix

# Variables
var weight {ASSETS} >=0 <=1;           # Asset weights
var portfolio_return = sum {i in ASSETS} weight[i] * expected_return[i];
# factor_exposure should be non-defined variables.
# Only instantiate if want_factor_model!=0
var factor_exposure {FACTORS: want_factor_model};
var portfolio_variance =
    if want_factor_model
        then
            sum {f in FACTORS} factor_exposure[f]^2
            + sum {a in ASSETS} asset_specific_risks[a] * weight[a]^2
    else
        sum {a1 in ASSETS, a2 in ASSETS}
            asset_cov[a1, a2] * weight[a1] * weight[a2];

# Objective: Minimize utility: expected return + portfolio variance
maximize Utility:
    portfolio_return - risk_free_rate / 2.0 * portfolio_variance;

# Constraints
subject to BudgetConstraint: 
    sum{i in ASSETS} weight[i] == 1;

# This definition constraint only instantiates
# if want_factor_model!=0
subject to FactorExposureDefinition{f in FACTORS: want_factor_model}:
    factor_exposure[f] == sum{i in ASSETS} weight[i] * factor_loadings[i, f];
Overwriting portfolio_sigma_factors.mod

Now we define two auxiliary functions to build an optimization model in either form using AMPLPY. Let’s start with a function for the traditional form (1):

def build_sigma_model(gamma, sigma, mu):
    ampl.reset()
    ampl.read("portfolio_sigma_factors.mod")
    ampl.param["want_factor_model"] = 0
    ampl.set["ASSETS"] = range(1, mu.shape[0] + 1)
    ampl.param["expected_return"] = mu
    ampl.param["factor_loadings"] = []
    ampl.param["asset_specific_risks"] = []
    ampl.param["asset_cov"] = sigma
    ampl.param["risk_free_rate"] = gamma

The second function builds the equivalent model (2):

def build_factor_model(gamma, B, d, mu):
    ampl.reset()
    ampl.read("portfolio_sigma_factors.mod")
    ampl.param["want_factor_model"] = 1
    ampl.set["ASSETS"] = range(1, mu.shape[0] + 1)
    ampl.set["FACTORS"] = range(1, B.shape[1] + 1)
    ampl.param["expected_return"] = mu
    ampl.param["factor_loadings"] = B
    ampl.param["asset_specific_risks"] = d
    ampl.param["asset_cov"] = []
    ampl.param["risk_free_rate"] = gamma

We are now ready to run a small benchmark. We will keep a fixed risk aversion coefficient \(\gamma\), and solve both models over a range of data with an increasing number of assets:

def RunBenchmark(
    ampl_options={"solver": "gurobi", "gurobi_options": {"numericfocus": 3}}
):
    np.random.seed(0xACAC)  # Fix seed for reproducibility

    num_factors = 72  # USE4 has 72 factors, too (see [1])
    timesteps = 700
    gamma = 0.025

    problem_dims = np.linspace(100, 750, 16, endpoint=True, dtype=int)
    time_sigma = []
    time_factor = []

    if "mp_options" not in ampl_options:
        ampl_options["mp_options"] = {}
    ampl_options["mp_options"]["tech:timing"] = 2  # For Initial.time_solver
    ampl.option = ampl_options

    for num_assets in problem_dims:
        X, sigma0, d, mu = factor_model(num_assets, num_factors, timesteps)

        print("Running with", num_assets, "of", problem_dims[-1], "assets: sigma...")
        sigma = X @ sigma0 @ X.T + np.diag(d)
        build_sigma_model(gamma, sigma, mu)
        ampl.snapshot("portfolio_sigma.run")
        ampl.solve()
        time_sigma.append(ampl.get_value("Initial.time_solver"))

        print(
            "Running with",
            num_assets,
            "of",
            problem_dims[-1],
            "assets: factor model...",
        )
        L = np.linalg.cholesky(sigma0)
        B = X @ L
        build_factor_model(gamma, B, d, mu)
        ampl.snapshot("portfolio_factors.run")
        ampl.solve()
        time_factor.append(ampl.get_value("Initial.time_solver"))

        print("   ...done  ---------------------------------------")

    return problem_dims, time_sigma, time_factor

Graphical output code#

def Plot(problem_dims, time_sigma, time_factor, caption):
    fig, ax = plt.subplots()
    ax.plot(problem_dims, time_sigma, c="blue", marker="o", label="sigma")
    ax.plot(problem_dims, time_factor, c="red", marker="o", label="factor")
    ax.legend()
    plt.title(caption)
    plt.xlabel("No. assets")
    plt.ylabel("Solution time (sec.)")
    plt.grid(True)
    plt.close(fig)

    return fig

Runner wrapper#

def BenchmarkSolver(solver, options={"gurobi_options": {"outlev": 0, "timing": 2}}):
    options["solver"] = solver
    p_dims, time_sigma, time_factor = RunBenchmark(options)
    fig = Plot(p_dims, time_sigma, time_factor, solver.capitalize() + " benchmark")

    return fig

Run with different solvers#

fig = BenchmarkSolver("gurobi")
Running with 100 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
/Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:34: runtime error: signed integer overflow: 33 * 489929840339196788 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:34 
/Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:37: runtime error: signed integer overflow: 7842240797665118548 + 6386558351771823828 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:37 
/Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:34: runtime error: signed integer overflow: 33 * 556558325256565636 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/massage.h:98:34 
/Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/collect.c:1424:9: runtime error: applying non-zero offset 8 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/collect.c:1424:9 
NL model read time = 0.022245s
NL model conversion time = 0.045357s

Gurobi 13.0.0: optimal solution; objective 2.889499366
0 simplex iterations
11 barrier iterations
Setup time = 0.081387s
Solver time = 0.007210s
Output time = 0.000009s
Total time = 0.088606s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 100 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.006218s
NL model conversion time = 0.008540s

Gurobi 13.0.0: optimal solution; objective 2.889499372
0 simplex iterations
14 barrier iterations
Setup time = 0.016534s
Solver time = 0.004845s
Output time = 0.000010s
Total time = 0.021390s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 143 of 750 assets: sigma...
Gurobi 13.0.0: 
/Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/func.c:1375:14: runtime error: member access within null pointer of type 'Library'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/gb5/Documents/prj/AMPL/escrow/cmake/acl/func.c:1375:14 
  tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.014339s
NL model conversion time = 0.082731s

Gurobi 13.0.0: optimal solution; objective 3.050585815
0 simplex iterations
12 barrier iterations
Setup time = 0.098607s
Solver time = 0.012008s
Output time = 0.000016s
Total time = 0.110631s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 143 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.006343s
NL model conversion time = 0.011266s

Gurobi 13.0.0: optimal solution; objective 3.050585815
0 simplex iterations
15 barrier iterations
Setup time = 0.019190s
Solver time = 0.006760s
Output time = 0.000010s
Total time = 0.025960s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 186 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.020559s
NL model conversion time = 0.139035s

Gurobi 13.0.0: optimal solution; objective 3.285445494
0 simplex iterations
13 barrier iterations
Setup time = 0.161120s
Solver time = 0.019432s
Output time = 0.000018s
Total time = 0.180570s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 186 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.006181s
NL model conversion time = 0.014015s

Gurobi 13.0.0: optimal solution; objective 3.285445494
0 simplex iterations
15 barrier iterations
Setup time = 0.021770s
Solver time = 0.008381s
Output time = 0.000008s
Total time = 0.030159s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 230 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.028753s
NL model conversion time = 0.212300s

Gurobi 13.0.0: optimal solution; objective 3.256968483
0 simplex iterations
13 barrier iterations
Setup time = 0.242593s
Solver time = 0.026633s
Output time = 0.000015s
Total time = 0.269241s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 230 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007897s
NL model conversion time = 0.016968s

Gurobi 13.0.0: optimal solution; objective 3.256968498
0 simplex iterations
16 barrier iterations
Setup time = 0.026446s
Solver time = 0.011402s
Output time = 0.000009s
Total time = 0.037857s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 273 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.038867s
NL model conversion time = 0.299201s

Gurobi 13.0.0: optimal solution; objective 3.405238096
0 simplex iterations
12 barrier iterations
Setup time = 0.339594s
Solver time = 0.035039s
Output time = 0.000016s
Total time = 0.374648s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 273 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007107s
NL model conversion time = 0.019740s

Gurobi 13.0.0: optimal solution; objective 3.405238098
0 simplex iterations
16 barrier iterations
Setup time = 0.028442s
Solver time = 0.011731s
Output time = 0.000009s
Total time = 0.040182s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 316 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.049610s
NL model conversion time = 0.400795s

Gurobi 13.0.0: optimal solution; objective 3.382498578
0 simplex iterations
14 barrier iterations
Setup time = 0.451923s
Solver time = 0.060313s
Output time = 0.000012s
Total time = 0.512249s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 316 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007126s
NL model conversion time = 0.022612s

Gurobi 13.0.0: optimal solution; objective 3.382498581
0 simplex iterations
17 barrier iterations
Setup time = 0.031235s
Solver time = 0.016410s
Output time = 0.000015s
Total time = 0.047659s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 360 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.063799s
NL model conversion time = 0.523210s

Gurobi 13.0.0: optimal solution; objective 3.727943459
0 simplex iterations
14 barrier iterations
Setup time = 0.588579s
Solver time = 0.073050s
Output time = 0.000014s
Total time = 0.661644s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 360 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007188s
NL model conversion time = 0.025309s

Gurobi 13.0.0: optimal solution; objective 3.727943459
0 simplex iterations
15 barrier iterations
Setup time = 0.033992s
Solver time = 0.012820s
Output time = 0.000014s
Total time = 0.046825s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 403 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.077972s
NL model conversion time = 0.656408s

Gurobi 13.0.0: optimal solution; objective 3.991145637
0 simplex iterations
13 barrier iterations
Setup time = 0.735927s
Solver time = 0.088037s
Output time = 0.000019s
Total time = 0.823982s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 403 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008917s
NL model conversion time = 0.028200s

Gurobi 13.0.0: optimal solution; objective 3.991145637
0 simplex iterations
15 barrier iterations
Setup time = 0.038662s
Solver time = 0.013863s
Output time = 0.000015s
Total time = 0.052541s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 446 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.092709s
NL model conversion time = 0.798175s

Gurobi 13.0.0: optimal solution; objective 3.951770561
0 simplex iterations
14 barrier iterations
Setup time = 0.892443s
Solver time = 0.099403s
Output time = 0.000016s
Total time = 0.991862s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 446 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007758s
NL model conversion time = 0.031332s

Gurobi 13.0.0: optimal solution; objective 3.951770564
0 simplex iterations
16 barrier iterations
Setup time = 0.040668s
Solver time = 0.015293s
Output time = 0.000008s
Total time = 0.055970s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 490 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.114746s
NL model conversion time = 0.969103s

Gurobi 13.0.0: optimal solution; objective 4.481524759
0 simplex iterations
14 barrier iterations
Setup time = 1.085351s
Solver time = 0.124003s
Output time = 0.000025s
Total time = 1.209378s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 490 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.007727s
NL model conversion time = 0.033897s

Gurobi 13.0.0: optimal solution; objective 4.481524758
0 simplex iterations
16 barrier iterations
Setup time = 0.043120s
Solver time = 0.015872s
Output time = 0.000013s
Total time = 0.059006s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 533 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.132315s
NL model conversion time = 1.140990s

Gurobi 13.0.0: optimal solution; objective 3.468383937
0 simplex iterations
13 barrier iterations
Setup time = 1.274868s
Solver time = 0.136554s
Output time = 0.000016s
Total time = 1.411439s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 533 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008151s
NL model conversion time = 0.036704s

Gurobi 13.0.0: optimal solution; objective 3.468383954
0 simplex iterations
16 barrier iterations
Setup time = 0.046366s
Solver time = 0.016214s
Output time = 0.000016s
Total time = 0.062596s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 576 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.152646s
NL model conversion time = 1.332237s

Gurobi 13.0.0: optimal solution; objective 3.947223252
0 simplex iterations
13 barrier iterations
Setup time = 1.486423s
Solver time = 0.158098s
Output time = 0.000018s
Total time = 1.644538s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 576 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008146s
NL model conversion time = 0.039494s

Gurobi 13.0.0: optimal solution; objective 3.947223235
0 simplex iterations
14 barrier iterations
Setup time = 0.049155s
Solver time = 0.015858s
Output time = 0.000014s
Total time = 0.065027s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 620 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.174984s
NL model conversion time = 1.538655s

Gurobi 13.0.0: optimal solution; objective 3.757197193
0 simplex iterations
14 barrier iterations
Setup time = 1.715182s
Solver time = 0.199303s
Output time = 0.000024s
Total time = 1.914509s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 620 of 750 assets: factor model...
  tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008704s
NL model conversion time = 0.042515s

Gurobi 13.0.0: optimal solution; objective 3.757197179
0 simplex iterations
15 barrier iterations
Setup time = 0.052794s
Solver time = 0.018532s
Output time = 0.000014s
Total time = 0.071340s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 663 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.200310s
NL model conversion time = 1.754369s

Gurobi 13.0.0: optimal solution; objective 3.890282998
0 simplex iterations
13 barrier iterations
Setup time = 1.956225s
Solver time = 0.219335s
Output time = 0.000021s
Total time = 2.175581s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 663 of 750 assets: factor model...
  tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008458s
NL model conversion time = 0.045424s

Gurobi 13.0.0: optimal solution; objective 3.890282997
0 simplex iterations
14 barrier iterations
Setup time = 0.055427s
Solver time = 0.017867s
Output time = 0.000014s
Total time = 0.073307s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 706 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.254625s
NL model conversion time = 2.012921s

Gurobi 13.0.0: optimal solution; objective 4.216462571
0 simplex iterations
14 barrier iterations
Setup time = 2.269083s
Solver time = 0.258094s
Output time = 0.000026s
Total time = 2.527203s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 706 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.008560s
NL model conversion time = 0.048164s

Gurobi 13.0.0: optimal solution; objective 4.216462566
0 simplex iterations
15 barrier iterations
Setup time = 0.058285s
Solver time = 0.018849s
Output time = 0.000011s
Total time = 0.077146s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 750 of 750 assets: sigma...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.330849s
NL model conversion time = 2.289885s

Gurobi 13.0.0: optimal solution; objective 4.084297931
0 simplex iterations
14 barrier iterations
Setup time = 2.622394s
Solver time = 0.303686s
Output time = 0.000023s
Total time = 2.926103s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 750 of 750 assets: factor model...
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 0
  tech:timing = 2
NL model read time = 0.009082s
NL model conversion time = 0.050856s

Gurobi 13.0.0: optimal solution; objective 4.08429793
0 simplex iterations
15 barrier iterations
Setup time = 0.061465s
Solver time = 0.020074s
Output time = 0.000015s
Total time = 0.081554s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
fig
../_images/e73eee7e394a8d5e4da985acddd0a0f8f48adc052cb2abab447502c143e3e8dc.png
fig = BenchmarkSolver("mosek")
Running with 100 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.003649s
NL model conversion time = 0.002614s

MOSEK 11.0.29: optimal, termination reason unknown; objective 2.889499379
0 simplex iterations
11 barrier iterations
Setup time = 0.010774s
Solver time = 0.008641s
Output time = 0.000004s
Total time = 0.019419s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 100 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.000780s
NL model conversion time = 0.000380s

MOSEK 11.0.29: optimal, termination reason unknown; objective 2.889499604
0 simplex iterations
10 barrier iterations
Setup time = 0.001513s
Solver time = 0.005062s
Output time = 0.000008s
Total time = 0.006583s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 143 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.003460s
NL model conversion time = 0.002965s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.050585172
0 simplex iterations
11 barrier iterations
Setup time = 0.006790s
Solver time = 0.008689s
Output time = 0.000005s
Total time = 0.015484s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 143 of 750 assets: factor model...
  tech:timing = 2
NL model read time = 0.000856s
NL model conversion time = 0.000481s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.05058624
0 simplex iterations
10 barrier iterations
Setup time = 0.001751s
Solver time = 0.006116s
Output time = 0.000008s
Total time = 0.007875s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 186 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.005474s
NL model conversion time = 0.004833s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.285445494
0 simplex iterations
10 barrier iterations
Setup time = 0.010676s
Solver time = 0.012178s
Output time = 0.000012s
Total time = 0.022865s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 186 of 750 assets: factor model...
  tech:timing = 2
NL model read time = 0.000863s
NL model conversion time = 0.000555s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.2854455
0 simplex iterations
9 barrier iterations
Setup time = 0.001781s
Solver time = 0.006979s
Output time = 0.000006s
Total time = 0.008766s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 230 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.008205s
NL model conversion time = 0.007580s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.256964287
0 simplex iterations
9 barrier iterations
Setup time = 0.016167s
Solver time = 0.017687s
Output time = 0.000008s
Total time = 0.033861s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 230 of 750 assets: factor model...
  tech:timing = 2
NL model read time = 0.000922s
NL model conversion time = 0.000612s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.25696976
0 simplex iterations
10 barrier iterations
Setup time = 0.001891s
Solver time = 0.008455s
Output time = 0.000006s
Total time = 0.010353s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 273 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.011388s
NL model conversion time = 0.011301s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.405237857
0 simplex iterations
8 barrier iterations
Setup time = 0.023060s
Solver time = 0.025908s
Output time = 0.000008s
Total time = 0.048976s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 273 of 750 assets: factor model...
  tech:timing = 2
NL model read time = 0.000905s
NL model conversion time = 0.000682s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.405238099
0 simplex iterations
10 barrier iterations
Setup time = 0.001956s
Solver time = 0.009566s
Output time = 0.000004s
Total time = 0.011527s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 316 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.014528s
NL model conversion time = 0.015442s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.38248968
0 simplex iterations
10 barrier iterations
Setup time = 0.030343s
Solver time = 0.035470s
Output time = 0.000006s
Total time = 0.065819s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 316 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.000993s
NL model conversion time = 0.000745s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.382499869
0 simplex iterations
10 barrier iterations
Setup time = 0.002138s
Solver time = 0.010682s
Output time = 0.000006s
Total time = 0.012826s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 360 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.019554s
NL model conversion time = 0.022926s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.727936326
0 simplex iterations
12 barrier iterations
Setup time = 0.042850s
Solver time = 0.047704s
Output time = 0.000009s
Total time = 0.090563s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 360 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001012s
NL model conversion time = 0.000845s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.727944316
0 simplex iterations
10 barrier iterations
Setup time = 0.002222s
Solver time = 0.011362s
Output time = 0.000004s
Total time = 0.013588s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 403 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.041465s
NL model conversion time = 0.027353s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.991143579
0 simplex iterations
9 barrier iterations
Setup time = 0.069183s
Solver time = 0.051676s
Output time = 0.000008s
Total time = 0.120867s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 403 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.000940s
NL model conversion time = 0.000907s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.991146675
0 simplex iterations
9 barrier iterations
Setup time = 0.002206s
Solver time = 0.012241s
Output time = 0.000004s
Total time = 0.014452s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 446 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.045737s
NL model conversion time = 0.033300s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.95175699
0 simplex iterations
9 barrier iterations
Setup time = 0.079407s
Solver time = 0.064274s
Output time = 0.000009s
Total time = 0.143690s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 446 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001058s
NL model conversion time = 0.000995s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.951770947
0 simplex iterations
11 barrier iterations
Setup time = 0.002405s
Solver time = 0.014635s
Output time = 0.000004s
Total time = 0.017043s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 490 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.058614s
NL model conversion time = 0.043068s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.481523355
0 simplex iterations
11 barrier iterations
Setup time = 0.102066s
Solver time = 0.082781s
Output time = 0.000012s
Total time = 0.184858s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 490 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001046s
NL model conversion time = 0.001072s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.481525298
0 simplex iterations
11 barrier iterations
Setup time = 0.002477s
Solver time = 0.015577s
Output time = 0.000004s
Total time = 0.018058s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 533 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.071716s
NL model conversion time = 0.050574s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.46836678
0 simplex iterations
10 barrier iterations
Setup time = 0.122670s
Solver time = 0.094526s
Output time = 0.000007s
Total time = 0.217203s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 533 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001089s
NL model conversion time = 0.001127s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.468384663
0 simplex iterations
11 barrier iterations
Setup time = 0.002579s
Solver time = 0.016884s
Output time = 0.000006s
Total time = 0.019469s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 576 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.076802s
NL model conversion time = 0.059633s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.94722303
0 simplex iterations
11 barrier iterations
Setup time = 0.136805s
Solver time = 0.111880s
Output time = 0.000010s
Total time = 0.248694s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 576 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001123s
NL model conversion time = 0.001195s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.94722337
0 simplex iterations
11 barrier iterations
Setup time = 0.002676s
Solver time = 0.017649s
Output time = 0.000014s
Total time = 0.020338s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 620 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.086316s
NL model conversion time = 0.065536s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.757192416
0 simplex iterations
12 barrier iterations
Setup time = 0.152226s
Solver time = 0.128890s
Output time = 0.000015s
Total time = 0.281131s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 620 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001188s
NL model conversion time = 0.001231s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.757199199
0 simplex iterations
10 barrier iterations
Setup time = 0.002776s
Solver time = 0.018406s
Output time = 0.000008s
Total time = 0.021189s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 663 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.105038s
NL model conversion time = 0.079371s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.890277622
0 simplex iterations
10 barrier iterations
Setup time = 0.184798s
Solver time = 0.135437s
Output time = 0.000009s
Total time = 0.320245s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 663 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001127s
NL model conversion time = 0.001332s

MOSEK 11.0.29: optimal, termination reason unknown; objective 3.890283607
0 simplex iterations
10 barrier iterations
Setup time = 0.002824s
Solver time = 0.019196s
Output time = 0.000013s
Total time = 0.022033s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 706 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.116002s
NL model conversion time = 0.089312s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.216458356
0 simplex iterations
11 barrier iterations
Setup time = 0.205695s
Solver time = 0.168408s
Output time = 0.000015s
Total time = 0.374118s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 706 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001140s
NL model conversion time = 0.001385s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.216462746
0 simplex iterations
12 barrier iterations
Setup time = 0.002885s
Solver time = 0.021844s
Output time = 0.000005s
Total time = 0.024734s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 750 of 750 assets: sigma...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.134174s
NL model conversion time = 0.097466s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.084297436
0 simplex iterations
11 barrier iterations
Setup time = 0.232026s
Solver time = 0.188301s
Output time = 0.000007s
Total time = 0.420334s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 750 of 750 assets: factor model...
MOSEK 11.0.29:   tech:timing = 2
NL model read time = 0.001184s
NL model conversion time = 0.001489s

MOSEK 11.0.29: optimal, termination reason unknown; objective 4.084300161
0 simplex iterations
11 barrier iterations
Setup time = 0.003049s
Solver time = 0.021503s
Output time = 0.000005s
Total time = 0.024557s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
fig
../_images/307cfef993f6e2f199390ecda16cb182682f825ad89e92e72ab9b73ae37bbc9e.png
fig = BenchmarkSolver("highs", {"highs_options": "tech:threads=8"})
Running with 100 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.002179s
NL model conversion time = 0.002870s

HiGHS 1.11.0: optimal solution; objective 2.889499379
0 simplex iterations
0 barrier iterations
Setup time = 0.010177s
Solver time = 0.002539s
Output time = 0.000006s
Total time = 0.012722s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 100 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000258s
NL model conversion time = 0.000458s

HiGHS 1.11.0: optimal solution; objective 2.889499379
0 simplex iterations
0 barrier iterations
Setup time = 0.001204s
Solver time = 0.004149s
Output time = 0.000004s
Total time = 0.005357s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 143 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.002907s
NL model conversion time = 0.002895s

HiGHS 1.11.0: optimal solution; objective 3.050585816
0 simplex iterations
0 barrier iterations
Setup time = 0.006295s
Solver time = 0.001572s
Output time = 0.000005s
Total time = 0.007873s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 143 of 750 assets: factor model...
  tech:timing = 2
  tech:threads = 8
NL model read time = 0.000271s
NL model conversion time = 0.000594s

HiGHS 1.11.0: optimal solution; objective 3.050585816
0 simplex iterations
0 barrier iterations
Setup time = 0.001342s
Solver time = 0.005852s
Output time = 0.000004s
Total time = 0.007198s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 186 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.004934s
NL model conversion time = 0.005013s

HiGHS 1.11.0: optimal solution; objective 3.285445494
0 simplex iterations
0 barrier iterations
Setup time = 0.010425s
Solver time = 0.002246s
Output time = 0.000007s
Total time = 0.012678s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 186 of 750 assets: factor model...
  tech:timing = 2
  tech:threads = 8
NL model read time = 0.000318s
NL model conversion time = 0.000692s

HiGHS 1.11.0: optimal solution; objective 3.285445494
0 simplex iterations
0 barrier iterations
Setup time = 0.001543s
Solver time = 0.007006s
Output time = 0.000003s
Total time = 0.008553s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 230 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.007705s
NL model conversion time = 0.007924s

HiGHS 1.11.0: optimal solution; objective 3.256968502
0 simplex iterations
0 barrier iterations
Setup time = 0.016122s
Solver time = 0.003050s
Output time = 0.000006s
Total time = 0.019178s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 230 of 750 assets: factor model...
  tech:timing = 2
  tech:threads = 8
NL model read time = 0.000337s
NL model conversion time = 0.000793s

HiGHS 1.11.0: optimal solution; objective 3.256968502
0 simplex iterations
0 barrier iterations
Setup time = 0.001596s
Solver time = 0.009040s
Output time = 0.000003s
Total time = 0.010639s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 273 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.010946s
NL model conversion time = 0.011876s

HiGHS 1.11.0: optimal solution; objective 3.405238098
0 simplex iterations
0 barrier iterations
Setup time = 0.023306s
Solver time = 0.003764s
Output time = 0.000005s
Total time = 0.027075s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 273 of 750 assets: factor model...
  tech:timing = 2
  tech:threads = 8
NL model read time = 0.000359s
NL model conversion time = 0.000871s

HiGHS 1.11.0: optimal solution; objective 3.405238098
0 simplex iterations
0 barrier iterations
Setup time = 0.001703s
Solver time = 0.009902s
Output time = 0.000004s
Total time = 0.011609s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 316 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.014008s
NL model conversion time = 0.016255s

HiGHS 1.11.0: optimal solution; objective 3.382498583
0 simplex iterations
0 barrier iterations
Setup time = 0.030740s
Solver time = 0.004803s
Output time = 0.000006s
Total time = 0.035548s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 316 of 750 assets: factor model...
  tech:timing = 2
  tech:threads = 8
NL model read time = 0.000385s
NL model conversion time = 0.001004s

HiGHS 1.11.0: optimal solution; objective 3.382498583
0 simplex iterations
0 barrier iterations
Setup time = 0.001901s
Solver time = 0.011957s
Output time = 0.000004s
Total time = 0.013862s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 360 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.033494s
NL model conversion time = 0.024397s

HiGHS 1.11.0: optimal solution; objective 3.727943459
0 simplex iterations
0 barrier iterations
Setup time = 0.058378s
Solver time = 0.005600s
Output time = 0.000007s
Total time = 0.063985s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 360 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000469s
NL model conversion time = 0.001069s

HiGHS 1.11.0: optimal solution; objective 3.727943459
0 simplex iterations
0 barrier iterations
Setup time = 0.002028s
Solver time = 0.012977s
Output time = 0.000004s
Total time = 0.015010s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 403 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.037225s
NL model conversion time = 0.028047s

HiGHS 1.11.0: optimal solution; objective 3.991145637
0 simplex iterations
0 barrier iterations
Setup time = 0.065760s
Solver time = 0.006812s
Output time = 0.000006s
Total time = 0.072578s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 403 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000438s
NL model conversion time = 0.001169s

HiGHS 1.11.0: optimal solution; objective 3.991145637
0 simplex iterations
0 barrier iterations
Setup time = 0.002109s
Solver time = 0.014813s
Output time = 0.000004s
Total time = 0.016926s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 446 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.049512s
NL model conversion time = 0.036083s

HiGHS 1.11.0: optimal solution; objective 3.951770573
0 simplex iterations
0 barrier iterations
Setup time = 0.086111s
Solver time = 0.007070s
Output time = 0.000008s
Total time = 0.093190s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 446 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000501s
NL model conversion time = 0.001277s

HiGHS 1.11.0: optimal solution; objective 3.951770573
0 simplex iterations
0 barrier iterations
Setup time = 0.002260s
Solver time = 0.015186s
Output time = 0.000005s
Total time = 0.017451s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 490 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.053276s
NL model conversion time = 0.046047s

HiGHS 1.11.0: optimal solution; objective 4.481524759
0 simplex iterations
0 barrier iterations
Setup time = 0.099799s
Solver time = 0.009082s
Output time = 0.000006s
Total time = 0.108887s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 490 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000515s
NL model conversion time = 0.001459s

HiGHS 1.11.0: optimal solution; objective 4.481524759
0 simplex iterations
0 barrier iterations
Setup time = 0.002452s
Solver time = 0.016788s
Output time = 0.000004s
Total time = 0.019245s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 533 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.074192s
NL model conversion time = 0.051626s

HiGHS 1.11.0: optimal solution; objective 3.468383954
0 simplex iterations
0 barrier iterations
Setup time = 0.126318s
Solver time = 0.010799s
Output time = 0.000006s
Total time = 0.137123s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 533 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000585s
NL model conversion time = 0.001549s

HiGHS 1.11.0: optimal solution; objective 3.468383954
0 simplex iterations
0 barrier iterations
Setup time = 0.002632s
Solver time = 0.020002s
Output time = 0.000004s
Total time = 0.022639s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 576 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.078626s
NL model conversion time = 0.063165s

HiGHS 1.11.0: optimal solution; objective 3.947223253
0 simplex iterations
0 barrier iterations
Setup time = 0.142292s
Solver time = 0.012429s
Output time = 0.000009s
Total time = 0.154730s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 576 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000559s
NL model conversion time = 0.001648s

HiGHS 1.11.0: optimal solution; objective 3.947223253
0 simplex iterations
0 barrier iterations
Setup time = 0.002708s
Solver time = 0.020986s
Output time = 0.000005s
Total time = 0.023699s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 620 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.098946s
NL model conversion time = 0.072297s

HiGHS 1.11.0: optimal solution; objective 3.757197201
0 simplex iterations
0 barrier iterations
Setup time = 0.171777s
Solver time = 0.012940s
Output time = 0.000007s
Total time = 0.184723s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 620 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000605s
NL model conversion time = 0.001706s

HiGHS 1.11.0: optimal solution; objective 3.757197201
0 simplex iterations
0 barrier iterations
Setup time = 0.002788s
Solver time = 0.022418s
Output time = 0.000005s
Total time = 0.025210s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 663 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.120306s
NL model conversion time = 0.086194s

HiGHS 1.11.0: optimal solution; objective 3.890282998
0 simplex iterations
0 barrier iterations
Setup time = 0.207005s
Solver time = 0.015977s
Output time = 0.000008s
Total time = 0.222990s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 663 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000679s
NL model conversion time = 0.001769s

HiGHS 1.11.0: optimal solution; objective 3.890282998
0 simplex iterations
0 barrier iterations
Setup time = 0.002942s
Solver time = 0.025320s
Output time = 0.000006s
Total time = 0.028268s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 706 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.130317s
NL model conversion time = 0.098204s

HiGHS 1.11.0: optimal solution; objective 4.216462576
0 simplex iterations
0 barrier iterations
Setup time = 0.229061s
Solver time = 0.016780s
Output time = 0.000009s
Total time = 0.245850s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 706 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000682s
NL model conversion time = 0.001949s

HiGHS 1.11.0: optimal solution; objective 4.216462576
0 simplex iterations
0 barrier iterations
Setup time = 0.003114s
Solver time = 0.023971s
Output time = 0.000005s
Total time = 0.027091s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
Running with 750 of 750 assets: sigma...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.146603s
NL model conversion time = 0.105291s

HiGHS 1.11.0: optimal solution; objective 4.084297931
0 simplex iterations
0 barrier iterations
Setup time = 0.252424s
Solver time = 0.020016s
Output time = 0.000010s
Total time = 0.272450s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
Running with 750 of 750 assets: factor model...
HiGHS 1.11.0:   tech:timing = 2
  tech:threads = 8
NL model read time = 0.000674s
NL model conversion time = 0.001997s

HiGHS 1.11.0: optimal solution; objective 4.084297931
0 simplex iterations
0 barrier iterations
Setup time = 0.003151s
Solver time = 0.028221s
Output time = 0.000005s
Total time = 0.031376s

suffix time OUT;
suffix time_read OUT;
suffix time_setup OUT;
suffix time_output OUT;
suffix time_solver OUT;
suffix time_conversion OUT;
   ...done  ---------------------------------------
fig
../_images/acf70af6fba78b2d38bd68ad2d2186755d920c04441e89c7cee2428f7cf04c9c.png

For Gurobi and Mosek, it is clear that the solve times of (2) are much smaller both in absolute and asymptotic terms. The data may appear somewhat nonsmooth over the problem dimensions. These are artifacts from multi-threading and different code paths in the computational kernels used for dense matrix multiplication. However HiGHS runs about 10x faster overall and the sigma model works better, which might be due to HiGHS presolve.

However, HiGHS cannot currently solve MIQP which would arise when adding discrete entities to the model, for example, a cardinality constraint (see the MP Modeling Guide):

n_positive = ampl.get_value("count {a in ASSETS} (weight[a] > 1e-4)")
n_pos_new = round(0.7 * n_positive)
print("Constrain to", n_pos_new, "assets from currently", n_positive)
ampl.eval(
    "s.t. Cardinality: atmost {} {{a in ASSETS}} (weight[a] > 0);".format(n_pos_new)
)
ampl.solve(solver="gurobi", gurobi_options="outlev=1", verbose=True)

print()
print(
    "New number of positive assets:",
    ampl.get_value("count {a in ASSETS} (weight[a] > 1e-4)"),
)
Constrain to 30 assets from currently 43
Gurobi 13.0.0:   tech:timing = 2
  tech:outlev = 1
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 2719854
Gurobi 13.0.0beta1 - expires 2025-12-02
WLS license 2719854 - registered to AMPL Optimization
NL model read time = 0.023518s

AMPL MP initial flat model has 822 variables (0 integer, 0 binary);
Objectives: 1 quadratic; 
Constraints:  74 linear;
Algebraic expressions:  1 count;
Logical expressions:  750 conditional (in)equalitie(s); 750 not;

AMPL MP final model has 2324 variables (2 integer, 1500 binary);
Objectives: 1 quadratic; 
Constraints:  825 linear;
Logical expressions:  750 indeq;


NL model conversion time = 0.079990s

Set parameter InfUnbdInfo to value 1
Gurobi Optimizer version 13.0.0 build v13.0.0beta1 (mac64[arm] - Darwin 24.6.0 24G90)

CPU model: Apple M1 Pro
Thread count: 8 physical cores, 8 logical processors, using up to 8 threads

Non-default parameters:
InfUnbdInfo  1

WLS license 2719854 - registered to AMPL Optimization
Optimize a model with 74 rows, 2324 columns and 54823 nonzeros (Max)
Model fingerprint: 0x537c43b5
Model has 750 linear objective coefficients
Model has 822 quadratic objective terms
Model has 750 simple general constraints
  750 INDICATOR
Model has 1 general nonlinear constraint (0 nonlinear terms)
Variable types: 1573 continuous, 751 integer (0 binary)
Coefficient statistics:
  Matrix range     [6e-05, 3e+01]
  Objective range  [5e-03, 8e+00]
  QObjective range [2e-02, 3e-02]
  Bounds range     [1e+00, 3e+01]
  RHS range        [1e+00, 3e+01]
  GenCon coe range [1e+00, 1e+00]
  NLCon coe range  [1e+00, 1e+00]

Warning: Completing partial solution with 751 unfixed non-continuous variables out of 751
User MIP start did not produce a new incumbent solution

Presolve added 750 rows and 0 columns
Presolve removed 0 rows and 752 columns
Presolve time: 0.19s
Presolved: 824 rows, 1572 columns, 57004 nonzeros
Presolved model has 822 quadratic objective terms
Variable types: 822 continuous, 750 integer (750 binary)
Found heuristic solution: objective 1.6199186

Root relaxation: objective 4.084298e+00, 2267 iterations, 0.16 seconds (0.47 work units)

    Nodes    |    Current Node    |     Objective Bounds      |     Work
 Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

     0     0    4.08430    0   40    1.61992    4.08430   152%     -    0s
Another try with MIP start
H    0     0                       1.8121056    4.08430   125%     -    0s
H    0     0                       2.0275529    4.08430   101%     -    0s
H    0     0                       2.1425597    4.08430  90.6%     -    0s
H    0     0                       2.1535301    4.08430  89.7%     -    0s
H    0     0                       2.6971230    4.08430  51.4%     -    0s
H    0     0                       2.7334972    4.08430  49.4%     -    0s
H    0     0                       2.7361581    4.08430  49.3%     -    0s
     0     0    4.08430    0   40    2.73616    4.08430  49.3%     -    0s
H    0     0                       3.2979051    4.08430  23.8%     -    0s
H    0     0                       3.3367343    4.08430  22.4%     -    0s
H    0     0                       3.3986239    4.08430  20.2%     -    0s
H    0     0                       3.4457379    4.08430  18.5%     -    0s
H    0     0                       3.4670127    4.08430  17.8%     -    0s
H    0     0                       3.4767013    4.08430  17.5%     -    0s
H    0     0                       3.4828032    4.08430  17.3%     -    0s
H    0     0                       3.4864062    4.08430  17.1%     -    0s
H    0     0                       3.6915189    4.08430  10.6%     -    1s
     0     2    4.08430    0   40    3.69152    4.08430  10.6%     -    1s
H   26    32                       3.7699421    4.08430  8.34%  20.6    1s
H   32    45                       3.9224948    4.08430  4.13%  22.0    1s
H   35    45                       4.0223700    4.08430  1.54%  20.6    1s
H  135   103                       4.0247193    4.08430  1.48%   8.7    1s
H  138   103                       4.0391176    4.08430  1.12%   8.6    1s
*  363   261              33       4.0496462    4.08420  0.85%   6.8    1s
*  373   267              31       4.0690503    4.08420  0.37%   6.9    1s
*  402   274              32       4.0690704    4.08412  0.37%   7.1    1s
*  659   390              37       4.0715829    4.08405  0.31%   6.7    1s
*  989   444              32       4.0718249    4.08318  0.28%   6.3    1s
* 1009   444              33       4.0727540    4.08318  0.26%   6.3    1s
* 1093   431              44       4.0752095    4.08310  0.19%   6.3    1s

Cutting planes:
  Implied bound: 20

Explored 4556 nodes (28440 simplex iterations) in 2.89 seconds (4.71 work units)
Thread count was 8 (of 8 available processors)

Solution count 10: 4.07521 4.07275 4.07182 ... 4.02237

Optimal solution found (tolerance 1.00e-04)
Best objective 4.075209453893e+00, best bound 4.075209453893e+00, gap 0.0000%
Gurobi 13.0.0: optimal solution; objective 4.075209454
28440 simplex iterations
4556 branching nodes
Setup time = 0.118529s
Solver time = 2.893763s
Output time = 0.000019s
Total time = 3.012311s

New number of positive assets: 30

Takeaways#

  • Incorporating explicit factors to model risk in an AMPL model is straightforward.

  • AMPL allows easy switching between state-of-the-art solvers.

  • Using factor risk models instead of the derived full covariance matrix can greatly improve solution time.