-
-
Notifications
You must be signed in to change notification settings - Fork 68
/
minimize.clj
123 lines (120 loc) · 4.93 KB
/
minimize.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;
; Copyright © 2017 Colin Smith.
; This work is based on the Scmutils system of MIT/GNU Scheme:
; Copyright © 2002 Massachusetts Institute of Technology
;
; This is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 3 of the License, or (at
; your option) any later version.
;
; This software is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this code; if not, see <http://www.gnu.org/licenses/>.
;
(ns sicmutils.numerical.minimize
(:require [clojure.tools.logging :as log])
(:import (org.apache.commons.math3.optim.univariate
BrentOptimizer
UnivariateObjectiveFunction
SearchInterval
UnivariatePointValuePair)
(org.apache.commons.math3.analysis
UnivariateFunction
MultivariateFunction)
(org.apache.commons.math3.optim.nonlinear.scalar
GoalType
ObjectiveFunction)
(org.apache.commons.math3.optim
MaxEval
OptimizationData
InitialGuess
ConvergenceChecker
SimpleValueChecker
PointValuePair)
(org.apache.commons.math3.optim.nonlinear.scalar.noderiv
SimplexOptimizer
NelderMeadSimplex)
(com.google.common.base Stopwatch)))
(defn minimize
"Find the minimum of the function f: R -> R in the interval [a,b]. If
observe is supplied, will be invoked with the iteration count and the
values of x and f(x) at each search step."
([f a b observe]
(let [total-time (Stopwatch/createStarted)
evaluation-time (Stopwatch/createUnstarted)
evaluation-count (atom 0)
rel 1e-5
abs 1e-5
o (BrentOptimizer.
rel abs
(reify ConvergenceChecker
(converged [_ _ _ current]
(when observe
(observe (.getPoint ^UnivariatePointValuePair current)
(.getValue ^UnivariatePointValuePair current)))
false)))
args ^"[Lorg.apache.commons.math3.optim.OptimizationData;"
(into-array OptimizationData
[(UnivariateObjectiveFunction.
(reify UnivariateFunction
(value [_ x]
(.start evaluation-time)
(swap! evaluation-count inc)
(let [fx (f x)]
(.stop evaluation-time)
fx))))
(MaxEval. 1000)
(SearchInterval. a b)
GoalType/MINIMIZE])
p (.optimize o args)]
(let [x (.getPoint p)
y (.getValue p)]
(when observe
(observe (dec (.getEvaluations o)) x y))
(log/info "#" @evaluation-count "total" (str total-time) "f" (str evaluation-time))
[x y @evaluation-count])))
([f a b]
(minimize f a b nil)))
(defn multidimensional-minimize
"Find the minimum of the function f: R^n -> R, given an initial point q ∈ R^n.
If observe is supplied, will be invoked with the iteration count and the values
of X and f(X) at each search step."
([f q observe]
(let [total-time (Stopwatch/createStarted)
evaluation-time (Stopwatch/createUnstarted)
evaluation-count (atom 0)
rel 1e-10
abs 1e-10
convergence-checker (SimpleValueChecker. rel abs)
o (SimplexOptimizer.
(reify ConvergenceChecker
(converged [_ iteration previous current]
(when observe
(observe (vec (.getPoint ^PointValuePair current))
(.getValue ^PointValuePair current)))
(.converged convergence-checker iteration previous current))))
args ^"[Lorg.apache.commons.math3.optim.OptimizationData;"
(into-array OptimizationData
[(NelderMeadSimplex. (count q))
(ObjectiveFunction.
(reify MultivariateFunction
(value [_ xs]
(.start evaluation-time)
(swap! evaluation-count inc)
(let [fxs (f xs)]
(.stop evaluation-time)
fxs))))
(MaxEval. 1000)
(InitialGuess. (double-array q))
GoalType/MINIMIZE])
p (.optimize o args)]
(.stop total-time)
(log/info "#" @evaluation-count "total" (str total-time) "f" (str evaluation-time))
(into [] (.getPoint p))))
([f q]
(multidimensional-minimize f q nil)))