srtree 3.0.0.4 → 3.0.0.5
raw patch · 4 files changed
+26/−8 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- ChangeLog.md +14/−0
- src/Algorithm/EqSat/SearchSR.hs +4/−1
- src/Algorithm/SRTree/NonlinearOpt.hs +7/−6
- srtree.cabal +1/−1
ChangeLog.md view
@@ -1,5 +1,19 @@ # Changelog for srtree +## 3.0.0.5++- **Fix NLopt re-entered thousands of times per fit** (`NonlinearOpt` + `SearchSR`):+ - `minimizeNLLWith` no longer `{-# INLINE #-}` and forces the NLopt result+ once (`t_opt `seq` nEvs `seq` ...`), so the optimization is not re-run at+ every use site. Previously GHC duplicated the lazy `where` thunk, re-entering+ NLopt ~tens of thousands of times for a single fit of expressions with a+ parameter in a division/log denominator (e.g. `t1/(x0+t1)`).+ - `fitnessFun` now `DeepSeq.force`s the `minimizeNLL'` result, so the parallel+ fit's forcing of both the fitness and the theta does not re-trigger the+ unshared optimization.+ - Effect: previously-hanging eggp fits (e.g. `gen=6, nPop=30`) now complete in+ ~1-9 s.+ ## 3.0.0.4 - **Export `createLoss`**: expose compiled loss function for external use
src/Algorithm/EqSat/SearchSR.hs view
@@ -122,7 +122,10 @@ else (val, theta) where nParams = countParamsUniq tree + if loss == NLL ROXY then 3 else if loss == NLL Gaussian then 1 else 0- (theta, lossVal, _) = minimizeNLL' VAR1 backend loss mYErr nIter x y tree thetaOrig+ -- force the NLopt result once so the parallel fit's `DeepSeq.force` of both+ -- the fitness and the theta never re-runs the optimization (which otherwise+ -- re-entered NLopt thousands of times for degenerate expressions).+ (theta, lossVal, _) = DeepSeq.force (minimizeNLL' VAR1 backend loss mYErr nIter x y tree thetaOrig) evalF a b c = negate $ compileLoss a (buildLoss loss (fromIntegral (V.length b)) tree) b c $ if nParams == 0 then thetaOrig else theta -- at folds=1 the validation split is the training data itself, so the -- train loss returned by minimizeNLL' already is the val loss; skipping
src/Algorithm/SRTree/NonlinearOpt.hs view
@@ -41,7 +41,11 @@ minimizeNLLWith funAndGrad alg niter t0 | niter == 0 = (t0, f, 0) | n == 0 = (t0, f, 0)- | otherwise = (t_opt', fst (funAndGrad t_opt), nEvs)+ | otherwise = let (t_opt, nEvs) = case minimizeLocal problem t0' of+ Right sol -> (solutionParams sol, nEvals sol)+ Left e -> (t0', 0)+ t_opt' = G.convert t_opt+ in t_opt `seq` nEvs `seq` (t_opt', fst (funAndGrad t_opt), nEvs) where t0' = G.convert t0 n = V.length t0@@ -51,11 +55,8 @@ algorithm = alg funAndGrad (Just $ VectorStorage $ fromIntegral n) stop = ObjectiveRelativeTolerance 1e-6 :| [ObjectiveAbsoluteTolerance 1e-6, MaximumEvaluations (fromIntegral niter)] problem = LocalProblem (fromIntegral n) stop algorithm- (t_opt, nEvs) = case minimizeLocal problem t0' of- Right sol -> (solutionParams sol, nEvals sol)- Left e -> (t0', 0)- t_opt' = G.convert t_opt-{-# INLINE minimizeNLLWith #-}+-- no INLINE: inlining duplicated the lazy `where` thunk so the NLopt call was+-- re-evaluated thousands of times per fit. -- | Compile the loss function and gradient for a tree, returning a reusable -- closure. Use this when you need to optimize the same expression with
srtree.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: srtree-version: 3.0.0.4+version: 3.0.0.5 synopsis: A general library to work with Symbolic Regression expression trees. description: A Symbolic Regression Tree data structure to work with mathematical expressions with support to first order derivative and simplification; license: BSD3