Source code for biogeme.latent_variables.resolved
from __future__ import annotations
"""Resolved semantic model used by all outputs."""
from dataclasses import dataclass, field
from enum import Enum
from .context import EstimationMode
from .model_spec import MeasurementModel
from .normalization_refs import ParameterRef
[docs]
class MeasurementErrorDistribution(str, Enum):
GAUSSIAN = 'gaussian'
LOGISTIC = 'logistic'
[docs]
class ThresholdConstructionKind(str, Enum):
SYMMETRIC = 'symmetric'
MONOTONE = 'monotone'
[docs]
class ParameterStatus(str, Enum):
FIXED = 'fixed'
FREE = 'free'
[docs]
class ParameterCreationKind(str, Enum):
NUMERIC_CONSTANT = 'numeric_constant'
FREE_BETA = 'free_beta'
FIXED_BETA = 'fixed_beta'
LOG_EXP_BETA = 'log_exp_beta'
BOUNDED_BETA = 'bounded_beta'
[docs]
class PositivityStrategy(str, Enum):
NONE = 'none'
LOG_EXP = 'log_exp'
LOWER_BOUND = 'lower_bound'
[docs]
class ParameterRole(str, Enum):
STRUCTURAL_INTERCEPT = 'structural_intercept'
STRUCTURAL_COEFFICIENT = 'structural_coefficient'
STRUCTURAL_SIGMA = 'structural_sigma'
MEASUREMENT_INTERCEPT = 'measurement_intercept'
MEASUREMENT_LOADING = 'measurement_loading'
MEASUREMENT_SIGMA = 'measurement_sigma'
THRESHOLD_FIRST = 'threshold_first'
THRESHOLD_DELTA = 'threshold_delta'
[docs]
class CutpointKind(str, Enum):
FREE = 'free'
FIXED = 'fixed'
DERIVED = 'derived'
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedParameter:
semantic_ref: ParameterRef | None
final_name: str
role: ParameterRole
status: ParameterStatus
fixed_value: float | None
initial_value: float
lower_bound: float | None
upper_bound: float | None
positivity_strategy: PositivityStrategy | None
creation_kind: ParameterCreationKind
notes: list[str] = field(default_factory=list)
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedParameterRef:
final_name: str
semantic_ref: ParameterRef | None = None
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedConstant:
value: float
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedLinearTerm:
coefficient: ResolvedParameterRef | ResolvedConstant
variable_name: str
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedLinearCombination:
intercept: ResolvedParameterRef | ResolvedConstant | None
terms: list[ResolvedLinearTerm]
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedStructuralEquation:
latent_name: str
expression_name: str
systematic_part: ResolvedLinearCombination
sigma: ResolvedParameterRef | None
draw_name: str
draw_type: str
error_distribution: str
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedCutpoint:
symbol_name: str
kind: CutpointKind
expression_text: str
source_parameter_names: list[str]
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedThresholdSystem:
type_name: str
symmetric: bool
categories: list[int]
neutral_labels: list[int]
construction_kind: ThresholdConstructionKind
cutpoints: list[ResolvedCutpoint]
used_by_indicators: list[str]
normalization_notes: list[str]
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedMeasurementEquation:
indicator_name: str
statement: str
type_name: str
measurement_model: MeasurementModel
systematic_part: ResolvedLinearCombination
sigma: ResolvedParameterRef | None
observed_variable_name: str
threshold_system_name: str | None
error_distribution: MeasurementErrorDistribution
normalization_notes: list[str]
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedNormalizationRule:
scope: str
target_name: str
value: float | str
reason: str
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedNormalizationSummary:
rules: list[ResolvedNormalizationRule]
warnings: list[str]
disclaimer: str
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedLatentVariable:
name: str
structural_equation: ResolvedStructuralEquation
indicator_names: list[str]
reference_indicator: str | None
normalization_notes: list[str]
[docs]
@dataclass(frozen=True, slots=True)
class ResolvedModel:
metadata: ResolvedModelMetadata
latent_variables: dict[str, ResolvedLatentVariable]
measurement_equations: dict[str, ResolvedMeasurementEquation]
threshold_systems: dict[str, ResolvedThresholdSystem]
parameters: dict[str, ResolvedParameter]
normalization: ResolvedNormalizationSummary
[docs]
def free_parameters(self) -> list[ResolvedParameter]:
"""Return the parameters that are estimated.
Fixed parameters and numeric constants are excluded because they do not
appear in the estimation results. The order follows the insertion order
of ``self.parameters``.
:return: list of free resolved parameters.
"""
return [
parameter
for parameter in self.parameters.values()
if parameter.status == ParameterStatus.FREE
]