Haskell で記述されている、または Haskell から簡単に呼び出すことができる、上限と下限、および不等式制約を使用した逐次非線形最適化用のライブラリはありますか?
3 に答える
bindings-levmarパッケージは、C Levenberg-Marquardt オプティマイザへのバインディングを提供します。
OPが一般的な最適化ライブラリを要求したことは知っています。私の経験は次のとおりです。
- levmarパッケージはblasおよび lapack ライブラリに依存しているため、インストールが非常に複雑になります。ghci がまだ Windows で動作するようにインストールすることはできませんでした。
- 非線形最適化パッケージには勾配関数が必要です
- 最適化パッケージにもグラデーションが必要なようですが、実際の使用方法はわかりませんでした。
さらに、言及されたすべてのパッケージには実際のドキュメントがないようです。
幸いなことに、単純な問題については単純な解決策で十分です。ブラケットで囲まれた極値を 1 つ持つ 1 次元の滑らかな凸関数を最適化したいが、勾配関数がわからない場合 ( 1を実行する場合は以下を参照)、黄金分割探索のような単純な方法で実行できます。
ウィキペディアのページから翻訳:
import Data.Maybe (fromMaybe)
-- 1 / phi
invphi = (sqrt 5 - 1) / 2
-- 1 / phi^2
invphi2 = (3 - sqrt 5) / 2
-- | Enable optional arguments syntax. Use with Maybe a as parameter type, then in the function write param // defaultValue
(//) :: Maybe a -> a -> a
(//) = flip fromMaybe
-- Just a wrapper function because of all the ugly Nothing's of the recursive function
goldenSectionSearch f a b tolerance = goldenSectionSearchRecursive f a b tolerance Nothing Nothing Nothing Nothing Nothing
-- | Golden section search, recursive.
-- Given a function f with a single local maximum in the interval [a, b], golden section search returns a subset interval [c, d] that contains the maximum with d-c <= tolerance
-- Taken from the python implementation at https://en.wikipedia.org/wiki/Golden-section_search
goldenSectionSearchRecursive ::
(Double -> Double) -- ^ Function with a single maximum in [a, b]
-> Double -- ^ One side of the interval
-> Double -- ^ Other side of the interval
-> Double -- ^ Tolerance
-> Maybe Double -- ^ h, Current search interval
-> Maybe Double -- ^ c, New left interval point. If Nothing, a new point is chosen.
-> Maybe Double -- ^ d, New right interval point.
-> Maybe Double -- ^ f(c), Function value at c
-> Maybe Double -- ^ f(d), Function value at d
-> (Double, Double) -- ^ The interval in which the maximum is
goldenSectionSearchRecursive f a' b' tolerance h' c' d' fc' fd'
| h < tolerance = (a, b)
| fc > fd = goldenSectionSearchRecursive f a d tolerance (Just (h * invphi)) Nothing (Just c) Nothing (Just fc)
| otherwise = goldenSectionSearchRecursive f c b tolerance (Just (h * invphi)) (Just d) Nothing (Just fd) Nothing
where
a = min a' b'
b = max a' b'
h = h' // (b - a)
c = c' // (a + invphi2 * h)
d = d' // (a + invphi * h)
fc = fc' // f c
fd = fd' // f d
そして、goldenSectionSearch (\x -> -(x-2)^2) 1 5 1e-5
which returnsを呼び出します(1.9999959837979107,2.0000050911830893)
。もちろん、この単純な関数は手で解くほうがはるかに簡単ですが、これは単なる例です。
PS 黄金分割探索の興味深い点は、収束率が正確にわかっていることです。反復ごとに、最適値が存在する間隔の長さが黄金比で除算されます。
PPS私はそれをGitHubに置きました
[ 1 ] 勾配関数がわかっている場合は、それをゼロに等しくして根を求める方法を適用すると、多くの場合、はるかに高速になることに注意してください。たとえば、ある次元では、Will Nessは、ゴールデン セクション検索よりも収束速度が速い単純な方法を持つ彼の答えを指摘しました。もちろん、勾配関数を必要とする前述のパッケージのいずれかを使用することもできます。