Skip to content

Commit c44d8d8

Browse files
Documentation/fix docstrings (#260)
Clean code, fix docstrings, fix docs
1 parent 7676036 commit c44d8d8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+167
-347
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "StructuralEquationModels"
22
uuid = "383ca8c5-e4ff-4104-b0a9-f7b279deed53"
33
authors = ["Maximilian Ernst", "Aaron Peikert"]
4-
version = "0.4.0"
4+
version = "0.4.1"
55

66
[deps]
77
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ The package makes use of
3939
- SparseArrays.jl to speed up symbolic computations.
4040
- Optim.jl and NLopt.jl to provide a range of different Optimizers/Linesearches.
4141
- ProximalAlgorithms.jl for regularization.
42-
- FiniteDiff.jl and ForwardDiff.jl to provide gradients for user-defined loss functions.
42+
- FiniteDiff.jl and to provide gradient approximations for user-defined loss functions.
4343

4444
# At the moment, we are still working on:
4545
- optimizing performance for big models (with hundreds of parameters)

docs/make.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ makedocs(
5252
"files" => "internals/files.md",
5353
"types" => "internals/types.md",
5454
],
55-
"Complementary material" => ["Mathematical appendix" => "complementary/maths.md"],
5655
],
5756
format = Documenter.HTML(
5857
prettyurls = get(ENV, "CI", nothing) == "true",

docs/src/developer/implied.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,8 @@ model per group and an additional model with `ImpliedEmpty` and `SemRidge` for t
6262
# Extended help
6363
6464
## Interfaces
65-
- `params(::RAMSymbolic) `-> Vector of parameter labels
66-
- `nparams(::RAMSymbolic)` -> Number of parameters
67-
68-
## Implementation
69-
Subtype of `SemImplied`.
65+
- `param_labels(::ImpliedEmpty) `-> Vector of parameter labels
66+
- `nparams(::ImpliedEmpty)` -> Number of parameters
7067
"""
7168
struct ImpliedEmpty{A, B, C} <: SemImplied
7269
hessianeval::A
@@ -78,7 +75,12 @@ end
7875
### Constructors
7976
############################################################################################
8077

81-
function ImpliedEmpty(;specification, meanstruct = NoMeanStruct(), hessianeval = ExactHessian(), kwargs...)
78+
function ImpliedEmpty(;
79+
specification,
80+
meanstruct = NoMeanStruct(),
81+
hessianeval = ExactHessian(),
82+
kwargs...,
83+
)
8284
return ImpliedEmpty(hessianeval, meanstruct, convert(RAMMatrices, specification))
8385
end
8486

docs/src/developer/loss.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ julia>?
204204

205205
help?> RAM
206206

207-
help?> SemObservedCommon
207+
help?> SemObservedData
208208
```
209209

210210
We see that the model implied covariance matrix can be assessed as `Σ(implied)` and the observed covariance matrix as `obs_cov(observed)`.

docs/src/developer/observed.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ nsamples(observed::MyObserved) = ...
2828
nobserved_vars(observed::MyObserved) = ...
2929
```
3030

31-
As always, you can add additional methods for properties that implied types and loss function want to access, for example (from the `SemObservedCommon` implementation):
31+
As always, you can add additional methods for properties that implied types and loss function want to access, for example (from the `SemObservedData` implementation):
3232

3333
```julia
34-
obs_cov(observed::SemObservedCommon) = observed.obs_cov
34+
obs_cov(observed::SemObservedData) = observed.obs_cov
3535
```

docs/src/developer/optimizer.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ options(optimizer::SemOptimizerName) = optimizer.options
3737
Note that your optimizer is a subtype of `SemOptimizer{:Name}`, where you can choose a `:Name` that can later be used as a keyword argument to `fit(engine = :Name)`.
3838
Similarly, `SemOptimizer{:Name}(args...; kwargs...) = SemOptimizerName(args...; kwargs...)` should be defined as well as a constructor that uses only keyword arguments:
3939

40-
´´´julia
40+
```julia
4141
SemOptimizerName(;
4242
algorithm = LBFGS(),
4343
options = Optim.Options(; f_tol = 1e-10, x_tol = 1.5e-8),
4444
kwargs...,
4545
) = SemOptimizerName(algorithm, options)
46-
´´´
46+
```
4747
A method for `update_observed` and additional methods might be usefull, but are not necessary.
4848

4949
Now comes the substantive part: We need to provide a method for `fit`:

docs/src/internals/files.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Source code is in the `"src"` folder:
1010
- `"StructuralEquationModels.jl"` defines the module and the exported objects
1111
- `"types.jl"` defines all abstract types and the basic type hierarchy
1212
- `"objective_gradient_hessian.jl"` contains methods for computing objective, gradient and hessian values for different model types as well as generic fallback methods
13-
- The four folders `"observed"`, `"implied"`, `"loss"` and `"diff"` contain implementations of specific subtypes (for example, the `"loss"` folder contains a file `"ML.jl"` that implements the `SemML` loss function).
13+
- The folders `"observed"`, `"implied"`, and `"loss"` contain implementations of specific subtypes (for example, the `"loss"` folder contains a file `"ML.jl"` that implements the `SemML` loss function).
1414
- `"optimizer"` contains connections to different optimization backends (aka methods for `fit`)
1515
- `"optim.jl"`: connection to the `Optim.jl` package
1616
- `"frontend"` contains user-facing functions

docs/src/internals/internals.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Internals and Design
22

3-
On the following pages, we document the internals and design of the package. Those informations are no prerequisite for extending the package (as decribed in the developer documentation)!, but they may be useful and hopefully interesting.
3+
On the following pages, we document some technical information about the package. Those informations are no prerequisite for extending the package (as decribed in the developer documentation)!, but they may be useful.

docs/src/performance/simulation.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# Simulation studies
22

3-
!!! note "Simulation study interface"
4-
We are currently working on an interface for simulation studies.
5-
Until we are finished with this, this page is just a collection of tips.
6-
73
## Replace observed data
84
In simulation studies, a common task is fitting the same model to many different datasets.
95
It would be a waste of resources to reconstruct the complete model for each dataset.

docs/src/tutorials/backends/nlopt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Using NLopt.jl
22

33
[`SemOptimizerNLopt`](@ref) implements the connection to `NLopt.jl`.
4-
It is only available if the `NLopt` package is loaded alongside `StructuralEquationModel.jl` in the running Julia session.
4+
It is only available if the `NLopt` package is loaded alongside `StructuralEquationModels.jl` in the running Julia session.
55
It takes a bunch of arguments:
66

77
```julia

docs/src/tutorials/construction/build_by_parts.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,21 @@ partable = ParameterTable(
4747
Now, we construct the different parts:
4848

4949
```@example build
50-
# observed ---------------------------------------------------------------------------------
50+
# observed -----------------------------------------------------------------------------
5151
observed = SemObservedData(specification = partable, data = data)
5252
53-
# implied ------------------------------------------------------------------------------------
53+
# implied ------------------------------------------------------------------------------
5454
implied_ram = RAM(specification = partable)
5555
56-
# loss -------------------------------------------------------------------------------------
56+
# loss ---------------------------------------------------------------------------------
5757
ml = SemML(observed = observed)
5858
5959
loss_ml = SemLoss(ml)
6060
61-
# optimizer -------------------------------------------------------------------------------------
61+
# optimizer ----------------------------------------------------------------------------
6262
optimizer = SemOptimizerOptim()
6363
64-
# model ------------------------------------------------------------------------------------
64+
# model --------------------------------------------------------------------------------
6565
6666
model_ml = Sem(observed, implied_ram, loss_ml)
6767

docs/src/tutorials/construction/outer_constructor.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ Structural Equation Model
1414
- Loss Functions
1515
SemML
1616
- Fields
17-
observed: SemObservedCommon
18-
implied: RAM
19-
optimizer: SemOptimizerOptim
17+
observed: SemObservedData
18+
implied: RAM
2019
```
2120

2221
The output of this call tells you exactly what model you just constructed (i.e. what the loss functions, observed, implied and optimizer parts are).

docs/src/tutorials/regularization/regularization.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ It can be used as
3030
```julia
3131
SemOptimizerProximal(
3232
algorithm = ProximalAlgorithms.PANOC(),
33-
options = Dict{Symbol, Any}(),
3433
operator_g,
3534
operator_h = nothing
3635
)
3736
```
3837

39-
The proximal operator (aka the regularization function) can be passed as `operator_g`, available options are listed [here](https://juliafirstorder.github.io/ProximalOperators.jl/stable/functions/).
38+
The proximal operator (aka the regularization function) can be passed as `operator_g`.
4039
The available Algorithms are listed [here](https://juliafirstorder.github.io/ProximalAlgorithms.jl/stable/guide/implemented_algorithms/).
4140

4241
## First example - lasso

src/additional_functions/helper.jl

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,84 +14,29 @@ function neumann_series(mat::SparseMatrixCSC; maxiter::Integer = size(mat, 1))
1414
return inverse
1515
end
1616

17-
#=
18-
function make_onelement_array(A)
19-
isa(A, Array) ? nothing : (A = [A])
20-
return A
21-
end
22-
=#
23-
24-
function semvec(observed, implied, loss, optimizer)
25-
observed = make_onelement_array(observed)
26-
implied = make_onelement_array(implied)
27-
loss = make_onelement_array(loss)
28-
optimizer = make_onelement_array(optimizer)
29-
30-
#sem_vec = Array{AbstractSem}(undef, maximum(length.([observed, implied, loss, optimizer])))
31-
sem_vec = Sem.(observed, implied, loss, optimizer)
32-
33-
return sem_vec
34-
end
35-
36-
skipmissing_mean(mat::AbstractMatrix) =
37-
[mean(skipmissing(coldata)) for coldata in eachcol(mat)]
38-
39-
function F_one_person(imp_mean, meandiff, inverse, data, logdet)
40-
F = logdet
41-
@. meandiff = data - imp_mean
42-
F += dot(meandiff, inverse, meandiff)
43-
return F
44-
end
45-
46-
function remove_all_missing(data::AbstractMatrix)
47-
keep = Vector{Int64}()
48-
for (i, coldata) in zip(axes(data, 1), eachrow(data))
49-
if any(!ismissing, coldata)
50-
push!(keep, i)
51-
end
52-
end
53-
return data[keep, :], keep
54-
end
55-
5617
function batch_inv!(fun, model)
5718
for i in 1:size(fun.inverses, 1)
5819
fun.inverses[i] .= LinearAlgebra.inv!(fun.choleskys[i])
5920
end
6021
end
6122

62-
#=
63-
function batch_sym_inv_update!(fun::Union{LossFunction, DiffFunction}, model)
64-
M_inv = inv(fun.choleskys[1])
65-
for i = 1:size(fun.inverses, 1)
66-
if size(model.observed.patterns_not[i]) == 0
67-
fun.inverses[i] .= M_inv
68-
else
69-
ind_not = model.observed.patterns_not[i]
70-
ind = model.observed.patterns[i]
71-
72-
A = M_inv[ind_not, ind]
73-
H = cholesky(M_inv[ind_not, ind_not])
74-
D = H \ A
75-
out = M_inv[ind, ind] - LinearAlgebra.BLAS.gemm('T', 'N', 1.0, A, D)
76-
fun.inverses[i] .= out
77-
end
78-
end
79-
end =#
80-
81-
function sparse_outer_mul!(C, A, B, ind) #computes A*S*B -> C, where ind gives the entries of S that are 1
23+
# computes A*S*B -> C, where ind gives the entries of S that are 1
24+
function sparse_outer_mul!(C, A, B, ind)
8225
fill!(C, 0.0)
8326
for i in 1:length(ind)
8427
BLAS.ger!(1.0, A[:, ind[i][1]], B[ind[i][2], :], C)
8528
end
8629
end
8730

88-
function sparse_outer_mul!(C, A, ind) #computes A*∇m, where ∇m ind gives the entries of ∇m that are 1
31+
# computes A*∇m, where ∇m ind gives the entries of ∇m that are 1
32+
function sparse_outer_mul!(C, A, ind)
8933
fill!(C, 0.0)
9034
@views C .= sum(A[:, ind], dims = 2)
9135
return C
9236
end
9337

94-
function sparse_outer_mul!(C, A, B::Vector, ind) #computes A*S*B -> C, where ind gives the entries of S that are 1
38+
# computes A*S*B -> C, where ind gives the entries of S that are 1
39+
function sparse_outer_mul!(C, A, B::Vector, ind)
9540
fill!(C, 0.0)
9641
@views @inbounds for i in 1:length(ind)
9742
C .+= B[ind[i][2]] .* A[:, ind[i][1]]

src/additional_functions/simulation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Return a new model with swaped observed part.
77
88
# Arguments
99
- `model::AbstractSemSingle`: model to swap the observed part of.
10-
- `kwargs`: additional keyword arguments; typically includes `data = ...`
10+
- `kwargs`: additional keyword arguments; typically includes `data` and `specification`
1111
- `observed`: Either an object of subtype of `SemObserved` or a subtype of `SemObserved`
1212
1313
# Examples

src/additional_functions/start_val/start_fabin3.jl

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ end
1818
# SemObservedMissing
1919
function start_fabin3(observed::SemObservedMissing, implied, args...; kwargs...)
2020
if !observed.em_model.fitted
21-
em_mvn(observed; kwargs...)
21+
em_mvn!(observed; kwargs...)
2222
end
2323

2424
return start_fabin3(implied.ram_matrices, observed.em_model.Σ, observed.em_model.μ)
@@ -45,24 +45,6 @@ function start_fabin3(
4545
)
4646
@assert length(F_var2obs) == size(F, 1)
4747

48-
# check in which matrix each parameter appears
49-
50-
#= in_S = length.(S_ind) .!= 0
51-
in_A = length.(A_ind) .!= 0
52-
A_ind_c = [linear2cartesian(ind, (n_var, n_var)) for ind in A_ind]
53-
in_Λ = [any(ind[2] .∈ F_ind) for ind in A_ind_c]
54-
55-
if !isnothing(M)
56-
in_M = length.(M_ind) .!= 0
57-
in_any = in_A .| in_S .| in_M
58-
else
59-
in_any = in_A .| in_S
60-
end
61-
62-
if !all(in_any)
63-
@warn "Could not determine fabin3 starting values for some parameters, default to 0."
64-
end =#
65-
6648
# set undirected parameters in S
6749
S_indices = CartesianIndices(S)
6850
for j in 1:nparams(S)
@@ -79,7 +61,6 @@ function start_fabin3(
7961

8062
# set loadings
8163
A_indices = CartesianIndices(A)
82-
# ind_Λ = findall([is_in_Λ(ind_vec, F_ind) for ind_vec in A_ind_c])
8364

8465
# collect latent variable indicators in A
8566
# maps latent parameter to the vector of dependent vars

src/additional_functions/start_val/start_simple.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ function start_simple(
6363
nparams(ram_matrices)
6464

6565
start_val = zeros(n_par)
66-
n_obs = nobserved_vars(ram_matrices)
6766
n_var = nvars(ram_matrices)
6867

6968
C_indices = CartesianIndices((n_var, n_var))

src/frontend/common.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# API methods supported by multiple SEM.jl types
22

33
"""
4-
params(semobj) -> Vector{Symbol}
4+
params(partable::ParameterTable) -> Vector{Symbol}
55
66
Return the vector of SEM model parameter identifiers.
77
"""
@@ -42,7 +42,7 @@ nlatent_vars(semobj) = length(latent_vars(semobj))
4242
"""
4343
param_indices(semobj)
4444
45-
Returns a dict of parameter names and their indices in `semobj`.
45+
Returns a dict of parameter labels and their indices in `semobj`.
4646
4747
# Examples
4848
```julia

src/frontend/fit/fitmeasures/fit_measures.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ end
1414
"""
1515
fit_measures(sem_fit, args...)
1616
17-
Return a default set of fit measures or the fit measures passed as `arg...`.
17+
Return a default set of fit measures or the fit measures passed as `args...`.
1818
"""
1919
function fit_measures end

src/frontend/fit/fitmeasures/minus2ll.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ end
4141
function minus2ll(observed::SemObservedMissing)
4242
# fit EM-based mean and cov if not yet fitted
4343
# FIXME EM could be very computationally expensive
44-
observed.em_model.fitted || em_mvn(observed)
44+
observed.em_model.fitted || em_mvn!(observed)
4545

4646
Σ = observed.em_model.Σ
4747
μ = observed.em_model.μ

0 commit comments

Comments
 (0)