Problem
The constrained_objective() function has an empty switch arm for CSM (Coherent Second Moment) at R/constrained_objective.R:606:
When a metaheuristic solver (DEoptim, GenSA, pso, random) encounters a CSM risk objective, it silently skips the objective — CSM contributes nothing to the penalty function. The optimizer has no signal to minimize CSM.
Root cause
CSM is defined as an optimization problem itself: CSM(w) = min_zeta { zeta + (1/alpha) * ||max(0, -Rw - zeta)||_2 }. Unlike variance or ES, it cannot be expressed as a closed-form function of moments — computing it requires solving an SOCP.
The extract_risk() function in extractrisk.R already implements this via CVXR. However, calling an SOCP solver for every constrained_objective() evaluation (thousands of times per metaheuristic run) raises performance concerns.
Proposed approach
- Extract the CSM SOCP computation from
extract_risk() into a standalone CSM() function
- Add
fun <- match.fun(CSM) to the switch arm in constrained_objective()
- Benchmark performance with metaheuristic solvers to assess viability
- Consider caching/warm-starting strategies if performance is prohibitive
Affected files
R/constrained_objective.R — empty CSM block (line 606)
R/extractrisk.R — existing CSM computation via CVXR (lines 44–49)
References
Discovered during optimization solvers vignette work. See plan.md Tier 3 section.
Problem
The
constrained_objective()function has an empty switch arm for CSM (Coherent Second Moment) atR/constrained_objective.R:606:When a metaheuristic solver (DEoptim, GenSA, pso, random) encounters a CSM risk objective, it silently skips the objective — CSM contributes nothing to the penalty function. The optimizer has no signal to minimize CSM.
Root cause
CSM is defined as an optimization problem itself:
CSM(w) = min_zeta { zeta + (1/alpha) * ||max(0, -Rw - zeta)||_2 }. Unlike variance or ES, it cannot be expressed as a closed-form function of moments — computing it requires solving an SOCP.The
extract_risk()function inextractrisk.Ralready implements this via CVXR. However, calling an SOCP solver for everyconstrained_objective()evaluation (thousands of times per metaheuristic run) raises performance concerns.Proposed approach
extract_risk()into a standaloneCSM()functionfun <- match.fun(CSM)to the switch arm inconstrained_objective()Affected files
R/constrained_objective.R— empty CSM block (line 606)R/extractrisk.R— existing CSM computation via CVXR (lines 44–49)References
Discovered during optimization solvers vignette work. See
plan.mdTier 3 section.