Skip to content

Commit 197ce3f

Browse files
Merge pull request #196 from alyst/fixes_1
Misc. fixes
2 parents 1589ca5 + 47ae507 commit 197ce3f

File tree

27 files changed

+162
-171
lines changed

27 files changed

+162
-171
lines changed

src/StructuralEquationModels.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using LinearAlgebra,
44
Optim,
55
NLSolversBase,
66
Statistics,
7+
StatsBase,
78
SparseArrays,
89
Symbolics,
910
NLopt,
@@ -18,6 +19,8 @@ using LinearAlgebra,
1819
import DataFrames: DataFrame
1920
export StenoGraphs, @StenoGraph, meld
2021

22+
const SEM = StructuralEquationModels
23+
2124
# type hierarchy
2225
include("types.jl")
2326
include("objective_gradient_hessian.jl")

src/additional_functions/helper.jl

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function neumann_series(mat::SparseMatrixCSC)
1010
return inverse
1111
end
1212

13-
#=
13+
#=
1414
function make_onelement_array(A)
1515
isa(A, Array) ? nothing : (A = [A])
1616
return A
@@ -108,11 +108,8 @@ function sparse_outer_mul!(C, A, B::Vector, ind) #computes A*S*B -> C, where ind
108108
end
109109

110110
function cov_and_mean(rows; corrected = false)
111-
data = transpose(reduce(hcat, rows))
112-
size(rows, 1) > 1 ? obs_cov = Statistics.cov(data; corrected = corrected) :
113-
obs_cov = reshape([0.0], 1, 1)
114-
obs_mean = vec(Statistics.mean(data, dims = 1))
115-
return obs_cov, obs_mean
111+
obs_mean, obs_cov = StatsBase.mean_and_cov(reduce(hcat, rows), 2, corrected = corrected)
112+
return obs_cov, vec(obs_mean)
116113
end
117114

118115
function duplication_matrix(nobs)

src/additional_functions/parameters.jl

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
function fill_A_S_M(A, S, M, A_indices, S_indices, M_indices, parameters)
2-
for (iA, iS, par) in zip(A_indices, S_indices, parameters)
1+
# fill A, S, and M matrices with the parameter values according to the parameters map
2+
function fill_A_S_M!(
3+
A::AbstractMatrix,
4+
S::AbstractMatrix,
5+
M::Union{AbstractVector, Nothing},
6+
A_indices::AbstractArrayParamsMap,
7+
S_indices::AbstractArrayParamsMap,
8+
M_indices::Union{AbstractArrayParamsMap, Nothing},
9+
parameters::AbstractVector,
10+
)
11+
@inbounds for (iA, iS, par) in zip(A_indices, S_indices, parameters)
312
for index_A in iA
413
A[index_A] = par
514
end
@@ -10,22 +19,28 @@ function fill_A_S_M(A, S, M, A_indices, S_indices, M_indices, parameters)
1019
end
1120

1221
if !isnothing(M)
13-
for (iM, par) in zip(M_indices, parameters)
22+
@inbounds for (iM, par) in zip(M_indices, parameters)
1423
for index_M in iM
1524
M[index_M] = par
1625
end
1726
end
1827
end
1928
end
2029

21-
function get_parameter_indices(parameters, M; linear = true, kwargs...)
22-
M_indices = [findall(x -> (x == par), M) for par in parameters]
23-
24-
if linear
25-
M_indices = cartesian2linear.(M_indices, [M])
30+
# build the map from the index of the parameter to the linear indices
31+
# of this parameter occurences in M
32+
# returns ArrayParamsMap object
33+
function array_parameters_map(parameters::AbstractVector, M::AbstractArray)
34+
params_index = Dict(param => i for (i, param) in enumerate(parameters))
35+
T = Base.eltype(eachindex(M))
36+
res = [Vector{T}() for _ in eachindex(parameters)]
37+
for (i, val) in enumerate(M)
38+
par_ind = get(params_index, val, nothing)
39+
if !isnothing(par_ind)
40+
push!(res[par_ind], i)
41+
end
2642
end
27-
28-
return M_indices
43+
return res
2944
end
3045

3146
function eachindex_lower(M; linear_indices = false, kwargs...)
@@ -49,9 +64,6 @@ function linear2cartesian(ind_lin, dims)
4964
return ind_cart
5065
end
5166

52-
cartesian2linear(ind_cart, A::AbstractArray) = cartesian2linear(ind_cart, size(A))
53-
linear2cartesian(ind_linear, A::AbstractArray) = linear2cartesian(ind_linear, size(A))
54-
5567
function set_constants!(M, M_pre)
5668
for index in eachindex(M)
5769
δ = tryparse(Float64, string(M[index]))
@@ -85,12 +97,18 @@ function get_matrix_derivative(M_indices, parameters, n_long)
8597
return ∇M
8698
end
8799

88-
function fill_matrix(M, M_indices, parameters)
100+
# fill M with parameters
101+
function fill_matrix!(
102+
M::AbstractMatrix,
103+
M_indices::AbstractArrayParamsMap,
104+
parameters::AbstractVector,
105+
)
89106
for (iM, par) in zip(M_indices, parameters)
90107
for index_M in iM
91108
M[index_M] = par
92109
end
93110
end
111+
return M
94112
end
95113

96114
function get_partition(A_indices, S_indices)

src/additional_functions/start_val/start_fabin3.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
start_fabin3(model)
3-
3+
44
Return a vector of FABIN 3 starting values (see Hägglund 1982).
55
Not available for ensemble models.
66
"""
@@ -58,8 +58,8 @@ function start_fabin3(ram_matrices::RAMMatrices, Σ, μ)
5858
if !isnothing(M)
5959
in_M = length.(M_ind) .!= 0
6060
in_any = in_A .| in_S .| in_M
61-
else
62-
in_any = in_A .| in_S
61+
else
62+
in_any = in_A .| in_S
6363
end
6464
6565
if !all(in_any)

src/diff/Empty.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ update_observed(optimizer::SemOptimizerEmpty, observed::SemObserved; kwargs...)
3434
############################################################################################
3535

3636
function Base.show(io::IO, struct_inst::SemOptimizerEmpty)
37-
StructuralEquationModels.print_type_name(io, struct_inst)
37+
print_type_name(io, struct_inst)
3838
end

src/frontend/fit/fitmeasures/n_obs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ n_obs(sem_fit::SemFit) = n_obs(sem_fit.model)
1313

1414
n_obs(model::AbstractSemSingle) = n_obs(model.observed)
1515

16-
n_obs(model::SemEnsemble) = sum(n_obs.(model.sems))
16+
n_obs(model::SemEnsemble) = sum(n_obs, model.sems)

src/frontend/fit/standard_errors/hessian.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Return hessian based standard errors.
55
66
# Arguments
7-
- `hessian`: how to compute the hessian. Options are
7+
- `hessian`: how to compute the hessian. Options are
88
- `:analytic`: (only if an analytic hessian for the model can be computed)
9-
- `:finitediff`: for finite difference approximation
9+
- `:finitediff`: for finite difference approximation
1010
"""
1111
function se_hessian(sem_fit::SemFit; hessian = :finitediff)
1212
c = H_scaling(sem_fit.model)
@@ -17,7 +17,7 @@ function se_hessian(sem_fit::SemFit; hessian = :finitediff)
1717
hessian!(H, sem_fit.model, sem_fit.solution)
1818
elseif hessian == :finitediff
1919
H = FiniteDiff.finite_difference_hessian(
20-
x -> objective!(sem_fit.model, x),
20+
Base.Fix1(objective!, sem_fit.model),
2121
sem_fit.solution,
2222
)
2323
elseif hessian == :optimizer
@@ -33,7 +33,7 @@ function se_hessian(sem_fit::SemFit; hessian = :finitediff)
3333
),
3434
)
3535
else
36-
throw(ArgumentError("I dont know how to compute `$hessian` standard-errors"))
36+
throw(ArgumentError("I don't know how to compute `$hessian` standard-errors"))
3737
end
3838

3939
invH = c * inv(H)

src/frontend/specification/EnsembleParameterTable.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function Dict(partable::EnsembleParameterTable)
2727
end
2828

2929
#= function DataFrame(
30-
partable::ParameterTable;
30+
partable::ParameterTable;
3131
columns = nothing)
3232
if isnothing(columns) columns = keys(partable.columns) end
3333
out = DataFrame([key => partable.columns[key] for key in columns])

src/frontend/specification/ParameterTable.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ update_partable!(partable::AbstractParameterTable, sem_fit::SemFit, vec, column)
224224
# update estimates -------------------------------------------------------------------------
225225
"""
226226
update_estimate!(
227-
partable::AbstractParameterTable,
227+
partable::AbstractParameterTable,
228228
sem_fit::SemFit)
229-
229+
230230
Write parameter estimates from `sem_fit` to the `:estimate` column of `partable`
231231
"""
232232
update_estimate!(partable::AbstractParameterTable, sem_fit::SemFit) =
@@ -236,7 +236,7 @@ update_estimate!(partable::AbstractParameterTable, sem_fit::SemFit) =
236236
"""
237237
update_start!(partable::AbstractParameterTable, sem_fit::SemFit)
238238
update_start!(partable::AbstractParameterTable, model::AbstractSem, start_val; kwargs...)
239-
239+
240240
Write starting values from `sem_fit` or `start_val` to the `:estimate` column of `partable`.
241241
242242
# Arguments
@@ -262,10 +262,10 @@ end
262262
# update partable standard errors ----------------------------------------------------------
263263
"""
264264
update_se_hessian!(
265-
partable::AbstractParameterTable,
266-
sem_fit::SemFit;
265+
partable::AbstractParameterTable,
266+
sem_fit::SemFit;
267267
hessian = :finitediff)
268-
268+
269269
Write hessian standard errors computed for `sem_fit` to the `:se` column of `partable`
270270
271271
# Arguments

src/frontend/specification/RAMMatrices.jl

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
### Type
33
############################################################################################
44

5+
# map from parameter index to linear indices of matrix/vector positions where it occurs
6+
AbstractArrayParamsMap = AbstractVector{<:AbstractVector{<:Integer}}
7+
ArrayParamsMap = Vector{Vector{Int}}
8+
59
struct RAMMatrices
6-
A_ind::Any
7-
S_ind::Any
8-
F_ind::Any
9-
M_ind::Any
10+
A_ind::ArrayParamsMap
11+
S_ind::ArrayParamsMap
12+
F_ind::Vector{Int}
13+
M_ind::Union{ArrayParamsMap, Nothing}
1014
parameters::Any
1115
colnames::Any
1216
constants::Any
@@ -18,9 +22,9 @@ end
1822
############################################################################################
1923

2024
function RAMMatrices(; A, S, F, M = nothing, parameters, colnames)
21-
A_indices = get_parameter_indices(parameters, A)
22-
S_indices = get_parameter_indices(parameters, S)
23-
isnothing(M) ? M_indices = nothing : M_indices = get_parameter_indices(parameters, M)
25+
A_indices = array_parameters_map(parameters, A)
26+
S_indices = array_parameters_map(parameters, S)
27+
M_indices = !isnothing(M) ? array_parameters_map(parameters, M) : nothing
2428
F_indices = findall([any(isone.(col)) for col in eachcol(F)])
2529
constants = get_RAMConstants(A, S, M)
2630
return RAMMatrices(
@@ -50,7 +54,7 @@ end
5054
import Base.==
5155

5256
function ==(c1::RAMConstant, c2::RAMConstant)
53-
res = ((c1.matrix == c2.matrix) & (c1.index == c2.index) & (c1.value == c2.value))
57+
res = ((c1.matrix == c2.matrix) && (c1.index == c2.index) && (c1.value == c2.value))
5458
return res
5559
end
5660

@@ -425,13 +429,13 @@ end
425429

426430
function ==(mat1::RAMMatrices, mat2::RAMMatrices)
427431
res = (
428-
(mat1.A_ind == mat2.A_ind) &
429-
(mat1.S_ind == mat2.S_ind) &
430-
(mat1.F_ind == mat2.F_ind) &
431-
(mat1.M_ind == mat2.M_ind) &
432-
(mat1.parameters == mat2.parameters) &
433-
(mat1.colnames == mat2.colnames) &
434-
(mat1.size_F == mat2.size_F) &
432+
(mat1.A_ind == mat2.A_ind) &&
433+
(mat1.S_ind == mat2.S_ind) &&
434+
(mat1.F_ind == mat2.F_ind) &&
435+
(mat1.M_ind == mat2.M_ind) &&
436+
(mat1.parameters == mat2.parameters) &&
437+
(mat1.colnames == mat2.colnames) &&
438+
(mat1.size_F == mat2.size_F) &&
435439
(mat1.constants == mat2.constants)
436440
)
437441
return res

0 commit comments

Comments
 (0)