123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #pragma once
- #include <Mathematics/GVector.h>
- #include <Mathematics/Minimize1.h>
- #include <cstring>
- namespace WwiseGTE
- {
- template <typename Real>
- class MinimizeN
- {
- public:
-
- MinimizeN(int dimensions, std::function<Real(Real const*)> const& F,
- int maxLevel, int maxBracket, int maxIterations, Real epsilon = (Real)1e-06)
- :
- mDimensions(dimensions),
- mFunction(F),
- mMaxIterations(maxIterations),
- mEpsilon(0),
- mDirections(dimensions + 1),
- mDConjIndex(dimensions),
- mDCurrIndex(0),
- mTCurr(dimensions),
- mTSave(dimensions),
- mMinimizer([this](Real t){ return mFunction(&(mTCurr + t * mDirections[mDCurrIndex])[0]); }, maxLevel, maxBracket)
- {
- SetEpsilon(epsilon);
- for (auto& direction : mDirections)
- {
- direction.SetSize(dimensions);
- }
- }
-
- inline void SetEpsilon(Real epsilon)
- {
- mEpsilon = (epsilon > (Real)0 ? epsilon : (Real)0);
- }
- inline Real GetEpsilon() const
- {
- return mEpsilon;
- }
-
-
-
-
-
- void GetMinimum(Real const* t0, Real const* t1, Real const* tInitial, Real* tMin, Real& fMin)
- {
-
- size_t numBytes = mDimensions * sizeof(Real);
- mFCurr = mFunction(tInitial);
- std::memcpy(&mTSave[0], tInitial, numBytes);
- std::memcpy(&mTCurr[0], tInitial, numBytes);
-
- for (int i = 0; i < mDimensions; ++i)
- {
- mDirections[i].MakeUnit(i);
- }
- Real ell0, ell1, ellMin;
- for (int iter = 0; iter < mMaxIterations; ++iter)
- {
- // Find minimum in each direction and update current location.
- for (int i = 0; i < mDimensions; ++i)
- {
- mDCurrIndex = i;
- ComputeDomain(t0, t1, ell0, ell1);
- mMinimizer.GetMinimum(ell0, ell1, (Real)0, ellMin, mFCurr);
- mTCurr += ellMin * mDirections[i];
- }
-
- mDirections[mDConjIndex] = mTCurr - mTSave;
- Real length = Length(mDirections[mDConjIndex]);
- if (length <= mEpsilon)
- {
-
-
- break;
- }
- mDirections[mDConjIndex] /= length;
-
- mDCurrIndex = mDConjIndex;
- ComputeDomain(t0, t1, ell0, ell1);
- mMinimizer.GetMinimum(ell0, ell1, (Real)0, ellMin, mFCurr);
- mTCurr += ellMin * mDirections[mDCurrIndex];
-
- mDConjIndex = 0;
- for (int i = 0; i < mDimensions; ++i)
- {
- mDirections[i] = mDirections[i + 1];
- }
-
- mTSave = mTCurr;
- }
- std::memcpy(tMin, &mTCurr[0], numBytes);
- fMin = mFCurr;
- }
- private:
-
-
-
-
-
- void ComputeDomain(Real const* t0, Real const* t1, Real& ell0, Real& ell1)
- {
- ell0 = -std::numeric_limits<Real>::max();
- ell1 = +std::numeric_limits<Real>::max();
- for (int i = 0; i < mDimensions; ++i)
- {
- Real value = mDirections[mDCurrIndex][i];
- if (value != (Real)0)
- {
- Real b0 = t0[i] - mTCurr[i];
- Real b1 = t1[i] - mTCurr[i];
- Real inv = ((Real)1) / value;
- if (value > (Real)0)
- {
-
- b0 *= inv;
- if (b0 > ell0)
- {
- ell0 = b0;
- }
- b1 *= inv;
- if (b1 < ell1)
- {
- ell1 = b1;
- }
- }
- else
- {
-
- b0 *= inv;
- if (b0 < ell1)
- {
- ell1 = b0;
- }
- b1 *= inv;
- if (b1 > ell0)
- {
- ell0 = b1;
- }
- }
- }
- }
-
- if (ell0 > (Real)0)
- {
- ell0 = (Real)0;
- }
- if (ell1 < (Real)0)
- {
- ell1 = (Real)0;
- }
- }
- int mDimensions;
- std::function<Real(Real const*)> mFunction;
- int mMaxIterations;
- Real mEpsilon;
- std::vector<GVector<Real>> mDirections;
- int mDConjIndex;
- int mDCurrIndex;
- GVector<Real> mTCurr;
- GVector<Real> mTSave;
- Real mFCurr;
- Minimize1<Real> mMinimizer;
- };
- }
|