Skip to content

Commit 4f88c75

Browse files
authored
feat: add nix, use hspec for tests, extended API, and dual cabal/stack support (#14)
* refactor: add hspec, nix, and switch to cabal + Use hspec with the existing golden tests + Use cabal instead of stack, and give deps some sensible constraints + Use nix flake to get cabal, ghc, etc. * feat: support non-negative and unbounded lower bounds in systems * test: ensure twoPhaseSimplex' gives the same result as twoPhaseSimplex * chore: replace twoPhaseSimplex with VarDomain version * feat (wip): VarDomain supports optional upper and lower bounds * chore: cleanup twoPhaseSimplex * feat: support a list of objective functions + useful if you want to optimise multiple vars with a single set of constraints + can also send 0 objective functions if you just want to run phase 1 * test: remove legacy types * chore: add Makefile, use make commands in workflow * chore: run formatter * chore: use nix in ci * chore: fix ci, haddocks, remove unused functions * chore: update flake lock * refactor: explicitly list imports for all unqualified Haskell imports * wip * refactor: add explicit import lists to all unqualified Haskell imports * chore: disable pull_request workflow trigger + we already trigger on every push * chore: fmt * chore: test more ghc versions * chore: update cabal/lsp versions, remove unsupported ghc from ci * chore: setup stack lts 22 * chore: remove broken ghc version + will fix it later * chore(haskell): formatting * chore(nix): switch to standard nix pin + iohk nix was too slow in ci without caching * chore(ci): align nix/non-nix fourmolu versions * chore(stack): use packages from resolver rather than pinning + and use stack ghc rather than system ghc * feat(Makefile): add stack support, default to cabal
1 parent 72d536a commit 4f88c75

21 files changed

Lines changed: 4405 additions & 1415 deletions

.github/workflows/haskell-nix.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Nix CI
2+
3+
on:
4+
push:
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
cabal:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
16+
17+
- name: Check Nix flake inputs
18+
uses: DeterminateSystems/flake-checker-action@3164002371bc90729c68af0e24d5aacf20d7c9f6 # v12
19+
20+
- name: Install Nix
21+
uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21
22+
23+
- name: Enable Nix cache
24+
uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13
25+
26+
- name: Build and test (cabal)
27+
run: |
28+
nix develop --command bash -c '
29+
# hsc2hs-generated test binaries crash in nix shells on Linux
30+
# ("stack smashing detected") due to hardening flags.
31+
# Replace hsc2hs with a wrapper that adds --cross-compile to
32+
# avoid running those binaries entirely.
33+
real=$(which hsc2hs)
34+
mkdir -p /tmp/bin
35+
printf "#!/bin/sh\nexec %s --cross-compile \"\$@\"\n" "$real" > /tmp/bin/hsc2hs
36+
chmod +x /tmp/bin/hsc2hs
37+
CABAL_CONFIGURE_FLAGS="--with-hsc2hs=/tmp/bin/hsc2hs" make ci
38+
'
39+
40+
stack:
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
45+
46+
- name: Install Nix
47+
uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21
48+
49+
- name: Enable Nix cache
50+
uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13
51+
52+
- name: Build and test (stack)
53+
run: nix develop --command make stack-ci
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Haskell CI (Stack)
2+
3+
on:
4+
push:
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
stack:
12+
name: Stack LTS 22.44 on ${{ matrix.os }}
13+
runs-on: ${{ matrix.os }}
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
os: [ubuntu-latest, macos-latest]
18+
19+
steps:
20+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21+
22+
- uses: haskell-actions/setup@v2
23+
id: setup
24+
with:
25+
ghc-version: '9.6'
26+
enable-stack: true
27+
28+
- name: Show toolchain versions
29+
shell: bash
30+
run: |
31+
ghc --numeric-version
32+
stack --numeric-version
33+
34+
- name: Cache Stack global package DB
35+
uses: actions/cache@v4
36+
with:
37+
path: ~/.stack
38+
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('simplex-method.cabal') }}
39+
restore-keys: |
40+
${{ runner.os }}-stack-global-
41+
42+
- name: Cache Stack work directory
43+
uses: actions/cache@v4
44+
with:
45+
path: .stack-work
46+
key: ${{ runner.os }}-stack-work-${{ hashFiles('stack.yaml') }}-${{ hashFiles('simplex-method.cabal') }}-${{ hashFiles('**/*.hs') }}
47+
restore-keys: |
48+
${{ runner.os }}-stack-work-${{ hashFiles('stack.yaml') }}-${{ hashFiles('simplex-method.cabal') }}-
49+
${{ runner.os }}-stack-work-
50+
51+
- name: Build dependencies
52+
run: stack build --system-ghc --only-dependencies --test
53+
54+
- name: Build the package
55+
run: stack build --system-ghc
56+
57+
- name: Run tests
58+
run: stack test --system-ghc

.github/workflows/haskell.yml

Lines changed: 40 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,129 +2,82 @@ name: Haskell CI
22

33
on:
44
push:
5-
branches:
6-
- '*'
7-
pull_request:
8-
branches: [ "master" ]
5+
workflow_dispatch:
96

107
permissions:
118
contents: read
129

1310
jobs:
1411
fourmolu:
15-
1612
runs-on: ubuntu-latest
17-
13+
1814
steps:
19-
- uses: actions/checkout@v3
20-
- uses: haskell-actions/run-fourmolu@v9
15+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
16+
17+
- uses: haskell-actions/run-fourmolu@015e6ed9db2b3f344482792d42b7317c764eb30f # v12
2118
with:
22-
version: "0.14.0.0"
19+
version: "0.15.0.0"
20+
2321
build:
2422
name: GHC ${{ matrix.ghc-version }} on ${{ matrix.os }}
2523
runs-on: ${{ matrix.os }}
2624
strategy:
2725
fail-fast: false
2826
matrix:
29-
os: [windows-latest, macos-latest, ubuntu-latest]
30-
ghc-version: ['9.6', '9.4', '9.2', '9.0']
27+
os: [ubuntu-latest, macos-latest, windows-latest]
28+
ghc-version: ['9.12', '9.10', '9.8', '9.6', '9.4', '9.2']
3129

3230
steps:
33-
- uses: actions/checkout@v3
31+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3432

3533
- name: Set up GHC ${{ matrix.ghc-version }}
36-
uses: haskell/actions/setup@v2
34+
uses: haskell-actions/setup@v2
3735
id: setup
3836
with:
3937
ghc-version: ${{ matrix.ghc-version }}
40-
enable-stack: true
38+
cabal-version: "3.16.1.0"
4139

42-
- name: Installed minor versions of GHC, Cabal, and Stack
40+
- name: Show toolchain versions
4341
shell: bash
4442
run: |
45-
GHC_VERSION=$(ghc --numeric-version)
46-
CABAL_VERSION=$(cabal --numeric-version)
47-
STACK_VERSION=$(stack --numeric-version)
48-
echo "GHC_VERSION=${GHC_VERSION}" >> "${GITHUB_ENV}"
49-
echo "CABAL_VERSION=${CABAL_VERSION}" >> "${GITHUB_ENV}"
50-
echo "STACK_VERSION=${STACK_VERSION}" >> "${GITHUB_ENV}"
43+
ghc --numeric-version
44+
cabal --numeric-version
45+
46+
- name: Check cabal file
47+
run: cabal check
48+
49+
- name: Update cabal package index
50+
run: cabal update
5151

5252
- name: Configure the build
5353
run: |
54-
# cabal configure --enable-tests --enable-benchmarks --disable-documentation
55-
# cabal build --dry-run
56-
stack build --test --bench --no-haddock --dry-run
57-
# The last step generates dist-newstyle/cache/plan.json for the cache key.
58-
59-
- name: Restore .stack-work cache
60-
uses: actions/cache/restore@v3
61-
id: cache-restore-stack-work
62-
with:
63-
path: .stack-work
64-
key: ${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-work-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}-${{ hashFiles('**/*.hs') }}
65-
restore-keys: |
66-
${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-work-
67-
68-
- name: Restore ~/.stack cache (Unix)
69-
uses: actions/cache/restore@v3
70-
id: cache-restore-stack-global-unix
71-
if: runner.os == 'Linux' || runner.os == 'macOS'
72-
with:
73-
path: ~/.stack
74-
key: ${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
75-
restore-keys: |
76-
${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-global-
54+
cabal configure --enable-tests --enable-benchmarks --disable-documentation
55+
cabal build --dry-run
7756
78-
- name: Restore %APPDATA%\stack, %LOCALAPPDATA%\Programs\stack cache (Windows)
79-
uses: actions/cache/restore@v3
80-
id: cache-restore-stack-global-windows
81-
if: runner.os == 'Windows'
57+
- name: Restore cabal store cache
58+
uses: actions/cache/restore@v4
59+
id: cache-restore
8260
with:
83-
path: |
84-
~\AppData\Roaming\stack
85-
~\AppData\Local\Programs\stack
86-
key: ${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
61+
path: ${{ steps.setup.outputs.cabal-store }}
62+
key: ${{ runner.os }}-ghc-${{ matrix.ghc-version }}-cabal-${{ hashFiles('**/plan.json') }}
8763
restore-keys: |
88-
${{ runner.os }}-ghc-${{ env.GHC_VERSION }}-stack-${{ env.STACK_VERSION }}-stack-global-
64+
${{ runner.os }}-ghc-${{ matrix.ghc-version }}-cabal-
8965
9066
- name: Build dependencies
91-
run: stack build --only-dependencies
92-
93-
- name: Build the package
94-
run: stack build
67+
run: cabal build --only-dependencies
9568

96-
- name: Save .stack-work cache
97-
uses: actions/cache/save@v3
98-
id: cache-save-stack-work
99-
if: steps.cache-restore-stack-work.outputs.cache-hit != 'true'
100-
with:
101-
path: .stack-work
102-
key: ${{ steps.cache-restore-stack-work.outputs.cache-primary-key }}
103-
104-
- name: Save %APPDATA%\stack, %LOCALAPPDATA%\Programs\stack cache (Windows)
105-
uses: actions/cache/save@v3
106-
if: runner.os == 'Windows'
107-
&& steps.cache-restore-stack-global-windows.outputs.cache-hit != 'true'
108-
with:
109-
path: |
110-
~\AppData\Roaming\stack
111-
~\AppData\Local\Programs\stack
112-
key: ${{ steps.cache-restore-stack-global-windows.outputs.cache-primary-key }}
113-
114-
- name: Save ~/.stack cache (Unix)
115-
uses: actions/cache/save@v3
116-
id: cache-save-stack-global
117-
if: (runner.os == 'Linux' || runner.os == 'macOS')
118-
&& steps.cache-restore-stack-global-unix.outputs.cache-hit != 'true'
69+
- name: Save cabal store cache
70+
uses: actions/cache/save@v4
71+
if: steps.cache-restore.outputs.cache-hit != 'true'
11972
with:
120-
path: ~/.stack
121-
key: ${{ steps.cache-restore-stack-global-unix.outputs.cache-primary-key }}
73+
path: ${{ steps.setup.outputs.cabal-store }}
74+
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
12275

123-
- name: Run tests
124-
run: stack test
76+
- name: Build the package
77+
run: cabal build all
12578

126-
- name: Check cabal file
127-
run: cabal check
79+
- name: Run tests
80+
run: cabal test all
12881

12982
- name: Build documentation
130-
run: stack haddock
83+
run: cabal haddock all --disable-documentation

.github/workflows/update-flake.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Update Nix Flake
2+
3+
on:
4+
schedule:
5+
# Every 2 weeks on Monday at 06:00 UTC
6+
- cron: "0 6 1,15 * *"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
13+
jobs:
14+
update-flake:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
19+
20+
- name: Install Nix
21+
uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21
22+
23+
- name: Enable Nix cache
24+
uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13
25+
26+
- name: Update flake lockfile
27+
run: nix flake update
28+
29+
- name: Create Pull Request
30+
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
31+
with:
32+
commit-message: "chore(nix): update flake lockfile"
33+
title: "chore(nix): update flake lockfile"
34+
body: |
35+
Automated flake lockfile update via `nix flake update`.
36+
37+
This PR was created by the scheduled update-flake workflow.
38+
Please review CI results before merging.
39+
branch: automation/update-flake-lock
40+
delete-branch: true
41+
labels: dependencies, automated

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
*~
33
dist-*/
44
.vscode/*
5+
.direnv/*
6+
.envrc
7+
cabal.project.local

ChangeLog.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
## Unreleased changes
44

5+
- **BREAKING CHANGE**: Restructured `VarDomain` type to support upper bounds
6+
- Replaced `NonNegative`, `LowerBound SimplexNum`, and `Unbounded` constructors with
7+
a single `Bounded { lowerBound :: Maybe SimplexNum, upperBound :: Maybe SimplexNum }` record
8+
- Added smart constructors for convenience: `unbounded`, `nonNegative`, `lowerBoundOnly`,
9+
`upperBoundOnly`, and `boundedRange`
10+
- `Bounded Nothing Nothing` is equivalent to `Unbounded`
11+
- `Bounded (Just 0) Nothing` is equivalent to `NonNegative`
12+
- Upper bounds are now supported and automatically added as LEQ constraints
13+
- Added `AddUpperBound` constructor to `VarTransform` for upper bound constraint generation
14+
- Updated `getTransform` to return a list of transforms (can now generate both lower and upper bound transforms)
15+
- Use Hspec for tests
16+
- Add nix flake
17+
- twoPhaseSimplex now takes a VarDomainMap (as the first param)
18+
- You can specify each Var's domain using smart constructors: `nonNegative`, `unbounded`,
19+
`lowerBoundOnly`, `upperBoundOnly`, or `boundedRange`
20+
- If a VarDomain for a Var is undefined, it's assumed to be `unbounded`
21+
- If you want to keep the same behaviour as before (all vars non-negative), use `nonNegative` for all Vars
22+
523
## [v0.2.0.0](https://github.com/rasheedja/LPPaver/tree/v0.2.0.0)
624

725
- Setup CI

0 commit comments

Comments
 (0)