Skip to content

Commit 3ef0eac

Browse files
committed
moving into docs
1 parent bd72181 commit 3ef0eac

6 files changed

Lines changed: 191 additions & 70 deletions

File tree

docs/make.jl

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1-
using Documenter
21
using AlgorithmicRecourseDynamics
2+
using Documenter
3+
4+
ex_meta = quote
5+
# Import module(s):
6+
using AlgorithmicRecourseDynamics
7+
end
8+
9+
DocMeta.setdocmeta!(AlgorithmicRecourseDynamics, :DocTestSetup, ex_meta; recursive = true)
310

4-
makedocs(
5-
sitename = "AlgorithmicRecourseDynamics",
6-
format = Documenter.HTML(),
7-
modules = [AlgorithmicRecourseDynamics]
11+
makedocs(;
12+
modules = [AlgorithmicRecourseDynamics],
13+
authors = "Patrick Altmeyer",
14+
repo = "https://github.com/pat-alt/AlgorithmicRecourseDynamics.jl/blob/{commit}{path}#{line}",
15+
sitename = "AlgorithmicRecourseDynamics.jl",
16+
format = Documenter.HTML(;
17+
prettyurls = get(ENV, "CI", "false") == "true",
18+
canonical = "https://pat-alt.github.io/AlgorithmicRecourseDynamics.jl",
19+
edit_link = "main",
20+
assets = String[],
21+
),
22+
pages = [
23+
"🏠 Home" => "index.md",
24+
"🎓 Research Paper" => [
25+
"Overview" => "paper/index.md",
26+
],
27+
"🧐 Reference" => "_reference.md",
28+
],
829
)
930

10-
# Documenter can also automatically deploy documentation to gh-pages.
11-
# See "Hosting Documentation" and deploydocs() in the Documenter manual
12-
# for more information.
13-
#=deploydocs(
14-
repo = "<repository url>"
15-
)=#
31+
deploydocs(; repo = "github.com/pat-alt/AlgorithmicRecourseDynamics.jl", devbranch = "main")

docs/src/_reference.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
```@meta
2+
CurrentModule = AlgorithmicRecourseDynamics
3+
```
4+
5+
# Reference
6+
7+
In this reference you will find a detailed overview of the package API.
8+
9+
> Reference guides are technical descriptions of the machinery and how to operate it. Reference material is information-oriented.
10+
>
11+
> --- [Diátaxis](https://diataxis.fr/reference/)
12+
13+
In other words, you come here because you want to take a very close look at the code 🧐
14+
15+
## Content
16+
17+
```@contents
18+
Pages = ["_reference.md"]
19+
```
20+
21+
## Index
22+
23+
```@index
24+
```
25+
26+
## Public Interface
27+
28+
```@autodocs
29+
Modules = [
30+
AlgorithmicRecourseDynamics
31+
]
32+
Private = false
33+
```
34+
35+
## Internal functions
36+
37+
```@autodocs
38+
Modules = [
39+
AlgorithmicRecourseDynamics
40+
]
41+
Public = false
42+
```

docs/src/paper/Project.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[deps]
2+
AlgorithmicRecourseDynamics = "3d1ede72-abb8-4340-bf8e-2ae06849b5ec"
3+
CounterfactualExplanations = "2f13d31b-18db-44c1-bc43-ebaf2cff0be0"
4+
Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c"
5+
LaplaceRedux = "c52c1a26-f7c5-402b-80be-ba1e638ad478"
6+
MLJBase = "a7f614a8-145f-11e9-1d2a-a57a1082229d"
7+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
8+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

docs/src/paper/index.qmd

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: Endogenous Macrodynamics in Algorithmic Recourse
3+
subtitle: Research Paper
4+
---
5+
6+
```@meta
7+
CurrentModule = ConformalPrediction
8+
```
9+
10+
This part of the documentation is specific to the research paper "Endogenous Macrodynamics in Algorithmic Recourse". To allow for reproducibility of the results at the time of publication, there is a specific package environment linked to this part of the documentation that **will not be updated**. It can be activated as follows:
11+
12+
```{julia}
13+
using Pkg; Pkg.activate("docs/src/paper")
14+
```
15+
16+
17+
The status of this package environment is shown below:
18+
19+
```{julia}
20+
#| output: true
21+
22+
Pkg.status()
23+
```
24+
25+
26+

docs/src/paper/proof_of_concept.qmd

Lines changed: 47 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,38 @@ jupyter: julia-1.7
44
---
55

66
```{julia}
7-
using Pkg; Pkg.activate("dev")
8-
```
7+
#| echo: false
98
9+
# Environment:
10+
using Pkg; Pkg.activate("docs/src/paper")
1011
11-
In this notebook we will use toy data to see how endogenous domain shifts and the resulting model shifts can have implications on the validity and cost of algorithmic recourse.
12+
# Deps:
13+
using CounterfactualExplanations
14+
using Flux
15+
using LaplaceRedux
16+
using MLJBase
17+
using Plots
18+
using Random
1219
13-
```{julia}
14-
include("dev/utils.jl")
15-
using AlgorithmicRecourseDynamics
16-
using CounterfactualExplanations, Flux, Plots, PlotThemes, Random, LaplaceRedux, LinearAlgebra
20+
# Setup
21+
Random.seed!(1234)
1722
theme(:wong)
18-
output_path = output_dir("poc")
19-
www_path = www_dir("poc")
23+
include("docs/src/utils.jl") # some helper functions
24+
output_path = output_dir("poc") # output directory for artifacts
25+
www_path = www_dir("poc") # output directory for images
2026
```
2127

28+
To start with, we will look at a proof-of-concept that demonstrates the main observation underlying that paper is framed around. In particular, we will use synthetic data to see how endogenous domain shifts and the resulting model shifts can have implications on the validity and cost of algorithmic recourse.
29+
2230
## Classifiers
2331

2432
```{julia}
25-
using MLJ
2633
N = 1000
27-
X, ys = make_blobs(N, 2; centers=2, as_table=false, center_box=(-2 => 2), cluster_std=0.1)
34+
xmax = 2
35+
X, ys = make_blobs(
36+
N, 2;
37+
centers=2, as_table=false, center_box=(-xmax => xmax), cluster_std=0.1
38+
)
2839
ys .= ys.==2
2940
X = X'
3041
xs = Flux.unstack(X,2)
@@ -35,65 +46,33 @@ counterfactual_data = CounterfactualData(X,ys')
3546
### Logistic Regression
3647

3748
```{julia}
38-
using Flux
49+
n_epochs = 10
3950
model = Chain(Dense(2,1))
40-
M = FluxModel(model)
51+
Models.forward!(model, data; loss=:logitbinarycrossentropy, opt=:Adam, n_epochs=n_epochs)
4152
```
4253

43-
4454
```{julia}
45-
n_epochs = 10
46-
using AlgorithmicRecourseDynamics.Models
47-
M = Models.train(M,counterfactual_data; n_epochs=n_epochs)
55+
model = Laplace(model, likelihood=:classification)
56+
LaplaceRedux.fit!(model, data) # fit Laplace Approximation
57+
optimize_prior!(model) # optimize prior
58+
mod = LaplaceReduxModel(model)
4859
```
4960

5061
```{julia}
51-
plt_nn = plot(M,counterfactual_data;zoom=0)
52-
savefig(plt_nn, joinpath(www_path, "nn_contour.png"))
53-
```
54-
55-
![](../artifacts/upload/www/synthetic/nn_contour.png)
56-
57-
### Laplace Redux
62+
#| output: true
63+
#| label: fig-model
64+
#| fig-cap: "The baseline model: contours indicate the predicted label; dots indicate observed data points."
5865
59-
```{julia}
60-
λ = 0.1
61-
model_laplace = Laplace(M.model, λ=λ)
62-
LaplaceRedux.fit!(model_laplace, data)
66+
plt_original = plot(mod, counterfactual_data; zoom=0, colorbar=false, title="(a)")
6367
```
6468

65-
```{julia}
66-
M_laplace = Models.LaplaceModel(model_laplace)
67-
```
68-
69-
```{julia}
70-
plt_laplace = plot(M_laplace, counterfactual_data;zoom=0)
71-
savefig(plt_laplace, joinpath(www_path, "la_contour.png"))
72-
```
73-
74-
![](../artifacts/upload/www/synthetic/la_contour.png)
75-
7669
## Single Round
7770

78-
```{julia}
79-
# Models:
80-
models = (Bayesian=M_laplace, Plugin=M)
81-
# Generators:
82-
generators = (
83-
Greedy=GreedyGenerator(loss=:logitbinarycrossentropy),
84-
Generic=GenericGenerator(loss=:logitbinarycrossentropy),
85-
REVISE=REVISEGenerator(loss=:logitbinarycrossentropy)
86-
)
87-
```
88-
8971
### Generate counterfactual
9072

9173
```{julia}
92-
cb = false
9374
γ = 0.75
94-
mod = M_laplace
95-
gen = generators[:Greedy]
96-
plt_original = plot(mod,counterfactual_data;zoom=0,colorbar=false,title="(a)")
75+
gen = GenericGenerator(;decision_threshold=γ)
9776
```
9877

9978
```{julia}
@@ -105,7 +84,7 @@ y′ = copy(ys)
10584
using CounterfactualExplanations.Counterfactuals: counterfactual, counterfactual_label
10685
for i in chosen
10786
x = X[:,i]
108-
outcome = generate_counterfactual(x, 1, counterfactual_data, mod, gen,γ=γ)
87+
outcome = generate_counterfactual(x, 1, counterfactual_data, mod, gen)
10988
X′[:,i] = counterfactual(outcome)
11089
y′[i] = first(counterfactual_label(outcome))
11190
end
@@ -116,7 +95,9 @@ plt_single = plot(mod,counterfactual_data′;zoom=0,colorbar=false,title="(b)")
11695
### Retrain
11796

11897
```{julia}
119-
mod = Models.train(mod, counterfactual_data′; n_epochs=n_epochs)
98+
Models.forward!(mod.model.model, data; loss=:logitbinarycrossentropy, opt=:Adam, n_epochs=n_epochs)
99+
LaplaceRedux.fit!(mod.model, data) # fit Laplace Approximation
100+
optimize_prior!(mod.model) # optimize prior
120101
plt_single_retrained = plot(mod,counterfactual_data′;zoom=0,colorbar=false,title="(c)")
121102
```
122103

@@ -129,10 +110,12 @@ while i <= 10
129110
candidates = findall(y′.==0)
130111
chosen = rand(candidates, Int(round(μ*length(candidates))))
131112
H₀ = mod.model.H # use posterior as new prior
132-
mod = Models.train(mod, counterfactual_data′; n_epochs=n_epochs, H₀=H₀)
113+
Models.forward!(mod.model.model, data; loss=:logitbinarycrossentropy, opt=:Adam, n_epochs=n_epochs)
114+
LaplaceRedux.fit!(mod.model, data) # fit Laplace Approximation
115+
optimize_prior!(mod.model) # optimize prior
133116
for i in chosen
134117
x = X′[:,i]
135-
outcome = generate_counterfactual(x, 1, counterfactual_data, mod, gen; γ=γ)
118+
outcome = generate_counterfactual(x, 1, counterfactual_data, mod, gen)
136119
X′[:,i] = counterfactual(outcome)
137120
y′[i] = first(counterfactual_label(outcome))
138121
end
@@ -143,7 +126,12 @@ plt_single_repeat = plot(mod,counterfactual_data′;zoom=0,colorbar=false,title=
143126

144127
```{julia}
145128
plt = plot(plt_original, plt_single, plt_single_retrained, plt_single_repeat, layout=(1,4), legend=false, axis=nothing, size=(600,165))
146-
savefig(plt, joinpath(www_path, "poc.png"))
129+
# savefig(plt, joinpath(www_path, "poc.png"))
147130
```
148131

132+
```{julia}
133+
134+
```
135+
136+
149137
![](../artifacts/upload/www/synthetic/poc.png)

docs/src/utils.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
output_dir(dir="")
3+
4+
Sets up the directory to save computational outputs and returns the path.
5+
"""
6+
function output_dir(dir="")
7+
root_ = "dev/artifacts/upload/output"
8+
output_dir = joinpath(root_, dir)
9+
if !isdir(output_dir)
10+
mkpath(output_dir)
11+
end
12+
return output_dir
13+
end
14+
15+
"""
16+
www_dir(dir="")
17+
18+
Sets up the directory to save images and returns the path.
19+
"""
20+
function www_dir(dir="")
21+
root_ = "dev/artifacts/upload/www"
22+
www_dir = joinpath(root_, dir)
23+
if !isdir(www_dir)
24+
mkpath(www_dir)
25+
end
26+
return www_dir
27+
end
28+
29+
"""
30+
data_dir(dir="")
31+
32+
Sets up the directory to save images and returns the path.
33+
"""
34+
function data_dir(dir="")
35+
root_ = "dev/artifacts/upload/data"
36+
data_dir = joinpath(root_, dir)
37+
if !isdir(data_dir)
38+
mkpath(data_dir)
39+
end
40+
return data_dir
41+
end

0 commit comments

Comments
 (0)