Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation with Documenter #46

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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", push_preview = true)
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
Loading