Skip to content

Commit

Permalink
Add documentation with Documenter (#46)
Browse files Browse the repository at this point in the history
* Initial Documenter documentation mainly based on README

* Add doctests

* Add documentation workflow

* Enable push_preview before deploying first time

* Add dev docs badge and disable docs preview
  • Loading branch information
hellemo authored Jun 28, 2024
1 parent 91c9055 commit ebed73b
Show file tree
Hide file tree
Showing 11 changed files with 1,741 additions and 2 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Documentation
on:
push:
branches: [main]
tags: '*'
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: '1'
- name: Install dependencies
shell: julia --color=yes --project=docs/ {0}
run: |
using Pkg
Pkg.develop(PackageSpec(path=pwd()))
Pkg.instantiate()
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key
run: julia --color=yes --project=docs/ docs/make.jl
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.vscode
/Manifest.toml
Manifest.toml
/tutorial/Manifest.toml
docs/build
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

[![Build Status](https://github.com/hellemo/SparseVariables.jl/workflows/CI/badge.svg?branch=main)](https://github.com/hellemo/SparseVariables.jl/actions?query=workflow%3ACI)
[![codecov](https://codecov.io/gh/hellemo/SparseVariables.jl/branch/main/graph/badge.svg?token=2LXGVU04YS)](https://codecov.io/gh/hellemo/SparseVariables.jl)
[![In Development](https://img.shields.io/badge/docs-dev-blue.svg)](https://sintefore.github.io/SparseVariables.jl/dev/)

Add container type(s) for improved performance and easier handling of sparse data
and sparse arrays of optimizaton variables in [JuMP](https://jump.dev/JuMP.jl/stable/).

Watch the JuliaCon/JuMP-dev 2022 lightning talk and check out the [notebook with examples and bencmarks]("docs/notebook_juliacon2022.jl"):
Watch the JuliaCon/JuMP-dev 2022 lightning talk and check out the [notebook with examples and benchmarks]("docs/notebook_juliacon2022.jl"):

[![SparseVariables - Efficient sparse modelling with JuMP](https://img.youtube.com/vi/YuDvfZo9W5A/3.jpg)](https://youtu.be/YuDvfZo9W5A)

Expand Down
8 changes: 8 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
SparseVariables = "2749762c-80ed-4b14-8f33-f0736679b02b"
24 changes: 24 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Documenter, JuMP, SparseVariables, HiGHS, CSV, DataFrames, PrettyTables

pages = [
"Introduction" => "index.md",
"Manual" => [
"Get started" => "manual/get_started.md",
"Benchmarks" => "manual/benchmarks.md",
],
"API reference" => "reference/api.md",
]

Documenter.makedocs(
sitename = "SparseVariables",
format = Documenter.HTML(;
prettyurls = get(ENV, "CI", "false") == "true",
edit_link = "main",
assets = String[],
),
doctest = true,
#modules = [SparseVariables],
pages = pages,
)

Documenter.deploydocs(; repo = "github.com/sintefore/SparseVariables.jl.git")
17 changes: 17 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SparseVariables

Add container type(s) for improved performance and easier handling of sparse data
and sparse arrays of optimizaton variables in [JuMP](https://jump.dev/JuMP.jl/stable/).

Watch the JuliaCon/JuMP-dev 2022 lightning talk and check out the [notebook with examples and benchmarks](https://github.com/sintefore/SparseVariables.jl/blob/main/%22docs/notebook_juliacon2022.jl):

[![SparseVariables - Efficient sparse modelling with JuMP](https://img.youtube.com/vi/YuDvfZo9W5A/3.jpg)](https://youtu.be/YuDvfZo9W5A)

Some motivational benchmark demonstrate that `SparseVariables` (`model_sparse`) can give similar performance to manually constructing efficent indices (`model_incremental`), but with a much simpler and and more modeller-friendly syntax, while outperforming alternative implementations:

![](manual/res.svg)

Time spent on model construction can vary a lot depending on the level of sparsity (here constructed by varying sparsity level through parameter `DP`):

![](manual/sparsity.svg)

9 changes: 9 additions & 0 deletions docs/src/manual/benchmarks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Benchmarks

Benchmarks of time spent on model construction with different number of variables (see [benchmark notebook for details](https://github.com/sintefore/SparseVariables.jl/blob/main/benchmark/benchmark.jl)) with [`IndexedVarArray`](@ref) (`model_indexed`) and `SparseAxisArray` (`model_sparse_aa`) illustrate the potential improvement in model generation time:

![](res.svg)

Time spent on model construction can vary a lot depending on the level of sparsity (here constructed by varying sparsity level through parameter `DP`):

![](sparsity.svg)
122 changes: 122 additions & 0 deletions docs/src/manual/get_started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Get Started

## Usage

```jldoctest readme_example
using JuMP
using SparseVariables
using HiGHS
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
# output
ERROR: BoundsError: attempt to access IndexedVarArray{VariableRef, 2, Tuple{String, Int64}} with 1 entry at index ["tesla", 2002]
```

```jldoctest readme_example
# 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)
# Solve m
set_optimizer(m, optimizer_with_attributes(HiGHS.Optimizer, MOI.Silent()=>true))
optimize!(m)
termination_status(m)
# output
OPTIMAL::TerminationStatusCode = 1
```

## Solution information

The [Tables.jl](https://github.com/JuliaData/Tables.jl) support has now been [upstreamed to JuMP](https://github.com/jump-dev/JuMP.jl/pull/3104), and is also supported for `IndexedVarArray`s, which makes it easy to get solutions for all indices at once and e.g. save to a CSV file or import into a `DataFrame`:

```jldoctest readme_example
# 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)
# output
4×3 DataFrame
Row │ car year value
│ String Int64 Float64
─────┼────────────────────────
1 │ bmw 2001 1.5
2 │ ford 2001 0.0
3 │ ford 2000 3.0
4 │ bmw 2002 1.0
```

The results may also be pretty-printed in the terminal using `PrettyTables`:

```jldoctest readme_example
using PrettyTables
pretty_table(tab)
# output
┌────────┬───────┬─────────┐
│ car │ year │ value │
│ String │ Int64 │ Float64 │
├────────┼───────┼─────────┤
│ bmw │ 2001 │ 1.5 │
│ ford │ 2001 │ 0.0 │
│ ford │ 2000 │ 3.0 │
│ bmw │ 2002 │ 1.0 │
└────────┴───────┴─────────┘
```
Loading

0 comments on commit ebed73b

Please sign in to comment.