Skip to content

sintefore/SparseVariables.jl

Repository files navigation

SparseVariables.jl

Build Status codecov In Development

Add container type(s) for improved performance and easier handling of sparse data and sparse arrays of optimizaton variables in JuMP.

Watch the JuliaCon/JuMP-dev 2022 lightning talk and check out the notebook with examples and benchmarks:

SparseVariables - Efficient sparse modelling with JuMP

2022-09: Updated benchmarks of time spent on model construction with different number of variables (see benchmark notebook for details) with additional types IndexedVarArray (model_indexed) and SparseAxisArray (model_sparse_aa) on current julia master:

Benchmarks with time spent on model construction with different level of sparsity:

Usage

using JuMP
using SparseVariables

const SV = SparseVariables

m = Model()

cars = ["ford", "bmw", "opel"]
years = [2000, 2001, 2002, 2003]

car_cost = SparseArray(Dict(
    ("ford", 2000) => 100,
    ("ford", 2001) => 150,
    ("bmw", 2001) => 200,
    ("bmw", 2002) => 300
    ))


# Empty variables with 2 indices and allowed index values specified
# by `car` and `year`, using `container=IndexedVarArray`
@variable(m, y[car=cars, year=years]; container=IndexedVarArray)
@variable(m, z[car=cars, year=years]; container=IndexedVarArray)
# Dynamic creation of variables
for (cr, yr) in keys(car_cost)
    insertvar!(y, cr, yr)
end

# Inserting values not in the defined value sets errors:
for c in ["opel", "tesla", "nikola"]
    insertvar!(z, c, 2002)
end

# Skip tests for allowed values for maximum performance.
# Note that this will allow creating values outside the defined
# sets, as long as the type is correct.
for c in ["opel", "tesla", "nikola"]
    unsafe_insertvar!(z, c, 2002)
end

# Inefficient iteration, but 0 contribution for non-existing variables
@constraint(m, sum(y[c,i] + z[c,i] for c in cars, i in years) <= 300)

# Slicing over selected indices
@constraint(m, sum(y[:, 2000]) <= 300)

# Efficient filtering using select syntax
for i in years
    @constraint(m, sum(car_cost[c,i] * y[c,i] for (c,i) in SV.select(y, :, i)) <= 300)
end

# Filter using functions on indices
@constraint(m, sum(z[endswith("a"), iseven]) >= 1)

Solution information

The Tables.jl support has now been upstreamed to JuMP, and is also supported for IndexedVarArrays:

using HiGHS

# Solve m
set_optimizer(m, HiGHS.Optimizer)
optimize!(m)

# Fetch solution
tab = JuMP.Containers.rowtable(value, y)

# Save to CSV
using CSV
CSV.write("result.csv", tab)

# Convert to DataFrame
using DataFrames
DataFrame(tab)

# Pretty print
using PrettyTables
pretty_table(tab)