123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <algorithm>
- #include <array>
- #include <vector>
- namespace WwiseGTE
- {
-
-
- template <typename Real, int... Dimensions>
- class LCPSolver {};
- template <typename Real>
- class LCPSolverShared
- {
- protected:
-
-
-
-
- LCPSolverShared(int n)
- :
- mNumIterations(0),
- mVarBasic(nullptr),
- mVarNonbasic(nullptr),
- mNumCols(0),
- mAugmented(nullptr),
- mQMin(nullptr),
- mMinRatio(nullptr),
- mRatio(nullptr),
- mPoly(nullptr),
- mZero((Real)0),
- mOne((Real)1)
- {
- if (n > 0)
- {
- mDimension = n;
- mMaxIterations = n * n;
- }
- else
- {
- mDimension = 0;
- mMaxIterations = 0;
- }
- }
-
-
-
-
- LCPSolverShared(int n, Real const& zero, Real const& one)
- :
- mNumIterations(0),
- mVarBasic(nullptr),
- mVarNonbasic(nullptr),
- mNumCols(0),
- mAugmented(nullptr),
- mQMin(nullptr),
- mMinRatio(nullptr),
- mRatio(nullptr),
- mPoly(nullptr),
- mZero(zero),
- mOne(one)
- {
- if (n > 0)
- {
- mDimension = n;
- mMaxIterations = n * n;
- }
- else
- {
- mDimension = 0;
- mMaxIterations = 0;
- }
- }
- public:
-
-
-
-
-
-
-
- inline void SetMaxIterations(int maxIterations)
- {
- mMaxIterations = (maxIterations > 0 ? maxIterations : mDimension * mDimension);
- }
- inline int GetMaxIterations() const
- {
- return mMaxIterations;
- }
-
- inline int GetNumIterations() const
- {
- return mNumIterations;
- }
- enum Result
- {
- HAS_TRIVIAL_SOLUTION,
- HAS_NONTRIVIAL_SOLUTION,
- NO_SOLUTION,
- FAILED_TO_CONVERGE,
- INVALID_INPUT
- };
- protected:
-
-
-
-
-
-
-
-
- struct Variable
- {
- char name;
- int index;
- int complementary;
- Real* tuple;
- };
-
-
-
-
-
-
-
-
-
-
-
-
- bool Solve(Real const* q, Real const* M, Real* w, Real* z, Result* result)
- {
-
-
-
-
- for (int r = 0; r < mDimension; ++r)
- {
- mPoly[r] = &Augmented(r, mDimension + 1);
- MakeZero(mPoly[r]);
- mPoly[r][0] = q[r];
- mPoly[r][r + 1] = mOne;
- }
-
- Copy(mPoly[0], mQMin);
- int basic = 0;
- for (int r = 1; r < mDimension; ++r)
- {
- if (LessThan(mPoly[r], mQMin))
- {
- Copy(mPoly[r], mQMin);
- basic = r;
- }
- }
- if (!LessThanZero(mQMin))
- {
- for (int r = 0; r < mDimension; ++r)
- {
- w[r] = q[r];
- z[r] = mZero;
- }
- if (result)
- {
- *result = HAS_TRIVIAL_SOLUTION;
- }
- return true;
- }
-
- for (int r = 0; r < mDimension; ++r)
- {
- for (int c = 0; c < mDimension; ++c)
- {
- Augmented(r, c) = M[c + mDimension * r];
- }
- Augmented(r, mDimension) = mOne;
- }
-
-
- for (int i = 0; i <= mDimension; ++i)
- {
- mVarBasic[i].name = 'w';
- mVarBasic[i].index = i;
- mVarBasic[i].complementary = i;
- mVarBasic[i].tuple = w;
- mVarNonbasic[i].name = 'z';
- mVarNonbasic[i].index = i;
- mVarNonbasic[i].complementary = i;
- mVarNonbasic[i].tuple = z;
- }
-
-
-
-
-
- int driving = mDimension;
- for (int r = 0; r < mDimension; ++r)
- {
- if (r != basic)
- {
- for (int c = 0; c < mNumCols; ++c)
- {
- if (c != mDimension)
- {
- Augmented(r, c) -= Augmented(basic, c);
- }
- }
- }
- }
- for (int c = 0; c < mNumCols; ++c)
- {
- if (c != mDimension)
- {
- Augmented(basic, c) = -Augmented(basic, c);
- }
- }
- mNumIterations = 0;
- for (int i = 0; i < mMaxIterations; ++i, ++mNumIterations)
- {
-
-
-
-
- int nextDriving = mVarBasic[basic].complementary;
- mVarNonbasic[nextDriving].complementary = driving;
- std::swap(mVarBasic[basic], mVarNonbasic[driving]);
- if (mVarNonbasic[driving].index == mDimension)
- {
-
- for (int r = 0; r < mDimension; ++r)
- {
- mVarBasic[r].tuple[mVarBasic[r].index] = mPoly[r][0];
- }
- for (int c = 0; c <= mDimension; ++c)
- {
- int index = mVarNonbasic[c].index;
- if (index < mDimension)
- {
- mVarNonbasic[c].tuple[index] = mZero;
- }
- }
- if (result)
- {
- *result = HAS_NONTRIVIAL_SOLUTION;
- }
- return true;
- }
-
-
-
- driving = nextDriving;
- basic = -1;
- for (int r = 0; r < mDimension; ++r)
- {
- if (Augmented(r, driving) < mZero)
- {
- Real factor = -mOne / Augmented(r, driving);
- Multiply(mPoly[r], factor, mRatio);
- if (basic == -1 || LessThan(mRatio, mMinRatio))
- {
- Copy(mRatio, mMinRatio);
- basic = r;
- }
- }
- }
- if (basic == -1)
- {
-
-
-
- for (int r = 0; r < mDimension; ++r)
- {
- w[r] = mZero;
- z[r] = mZero;
- }
- if (result)
- {
- *result = NO_SOLUTION;
- }
- return false;
- }
-
-
- Real invDenom = mOne / Augmented(basic, driving);
- for (int r = 0; r < mDimension; ++r)
- {
- if (r != basic && Augmented(r, driving) != mZero)
- {
- Real multiplier = Augmented(r, driving) * invDenom;
- for (int c = 0; c < mNumCols; ++c)
- {
- if (c != driving)
- {
- Augmented(r, c) -= Augmented(basic, c) * multiplier;
- }
- else
- {
- Augmented(r, driving) = multiplier;
- }
- }
- }
- }
- for (int c = 0; c < mNumCols; ++c)
- {
- if (c != driving)
- {
- Augmented(basic, c) = -Augmented(basic, c) * invDenom;
- }
- else
- {
- Augmented(basic, driving) = invDenom;
- }
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #if defined(GTE_THROW_ON_LCPSOLVER_ERRORS)
- LogError("LCPSolverShared::Solve failed to converge.");
- #endif
- if (result)
- {
- *result = FAILED_TO_CONVERGE;
- }
- return false;
- }
-
- inline Real const& Augmented(int row, int col) const
- {
- return mAugmented[col + mNumCols * row];
- }
- inline Real& Augmented(int row, int col)
- {
- return mAugmented[col + mNumCols * row];
- }
-
-
- void MakeZero(Real* poly)
- {
- for (int i = 0; i <= mDimension; ++i)
- {
- poly[i] = mZero;
- }
- }
- void Copy(Real const* poly0, Real* poly1)
- {
- for (int i = 0; i <= mDimension; ++i)
- {
- poly1[i] = poly0[i];
- }
- }
- bool LessThan(Real const* poly0, Real const* poly1)
- {
- for (int i = 0; i <= mDimension; ++i)
- {
- if (poly0[i] < poly1[i])
- {
- return true;
- }
- if (poly0[i] > poly1[i])
- {
- return false;
- }
- }
- return false;
- }
- bool LessThanZero(Real const* poly)
- {
- for (int i = 0; i <= mDimension; ++i)
- {
- if (poly[i] < mZero)
- {
- return true;
- }
- if (poly[i] > mZero)
- {
- return false;
- }
- }
- return false;
- }
- void Multiply(Real const* poly, Real scalar, Real* product)
- {
- for (int i = 0; i <= mDimension; ++i)
- {
- product[i] = poly[i] * scalar;
- }
- }
- int mDimension;
- int mMaxIterations;
- int mNumIterations;
-
-
-
-
-
-
- Variable* mVarBasic;
- Variable* mVarNonbasic;
- int mNumCols;
- Real* mAugmented;
- Real* mQMin;
- Real* mMinRatio;
- Real* mRatio;
- Real** mPoly;
- Real mZero, mOne;
- };
- template <typename Real, int n>
- class LCPSolver<Real, n> : public LCPSolverShared<Real>
- {
- public:
-
-
- LCPSolver()
- :
- LCPSolverShared<Real>(n)
- {
- this->mVarBasic = mArrayVarBasic.data();
- this->mVarNonbasic = mArrayVarNonbasic.data();
- this->mNumCols = 2 * (n + 1);
- this->mAugmented = mArrayAugmented.data();
- this->mQMin = mArrayQMin.data();
- this->mMinRatio = mArrayMinRatio.data();
- this->mRatio = mArrayRatio.data();
- this->mPoly = mArrayPoly.data();
- }
-
-
-
-
- LCPSolver(Real const& zero, Real const& one)
- :
- LCPSolverShared<Real>(n, zero, one)
- {
- this->mVarBasic = mArrayVarBasic.data();
- this->mVarNonbasic = mArrayVarNonbasic.data();
- this->mNumCols = 2 * (n + 1);
- this->mAugmented = mArrayAugmented.data();
- this->mQMin = mArrayQMin.data();
- this->mMinRatio = mArrayMinRatio.data();
- this->mRatio = mArrayRatio.data();
- this->mPoly = mArrayPoly.data();
- }
-
-
-
- bool Solve(std::array<Real, n> const& q, std::array<std::array<Real, n>, n> const& M,
- std::array<Real, n>& w, std::array<Real, n>& z,
- typename LCPSolverShared<Real>::Result* result = nullptr)
- {
- return LCPSolverShared<Real>::Solve(q.data(), M.front().data(), w.data(), z.data(), result);
- }
- private:
- std::array<typename LCPSolverShared<Real>::Variable, n + 1> mArrayVarBasic;
- std::array<typename LCPSolverShared<Real>::Variable, n + 1> mArrayVarNonbasic;
- std::array<Real, 2 * (n + 1)* n> mArrayAugmented;
- std::array<Real, n + 1> mArrayQMin;
- std::array<Real, n + 1> mArrayMinRatio;
- std::array<Real, n + 1> mArrayRatio;
- std::array<Real*, n> mArrayPoly;
- };
- template <typename Real>
- class LCPSolver<Real> : public LCPSolverShared<Real>
- {
- public:
-
-
- LCPSolver(int n)
- :
- LCPSolverShared<Real>(n)
- {
- if (n > 0)
- {
- mVectorVarBasic.resize(n + 1);
- mVectorVarNonbasic.resize(n + 1);
- mVectorAugmented.resize(2 * (n + 1) * n);
- mVectorQMin.resize(n + 1);
- mVectorMinRatio.resize(n + 1);
- mVectorRatio.resize(n + 1);
- mVectorPoly.resize(n);
- this->mVarBasic = mVectorVarBasic.data();
- this->mVarNonbasic = mVectorVarNonbasic.data();
- this->mNumCols = 2 * (n + 1);
- this->mAugmented = mVectorAugmented.data();
- this->mQMin = mVectorQMin.data();
- this->mMinRatio = mVectorMinRatio.data();
- this->mRatio = mVectorRatio.data();
- this->mPoly = mVectorPoly.data();
- }
- }
-
-
-
-
-
- bool Solve(std::vector<Real> const& q, std::vector<Real> const& M,
- std::vector<Real>& w, std::vector<Real>& z,
- typename LCPSolverShared<Real>::Result* result = nullptr)
- {
- if (this->mDimension > static_cast<int>(q.size())
- || this->mDimension * this->mDimension > static_cast<int>(M.size()))
- {
- if (result)
- {
- *result = this->INVALID_INPUT;
- }
- return false;
- }
- if (this->mDimension > static_cast<int>(w.size()))
- {
- w.resize(this->mDimension);
- }
- if (this->mDimension > static_cast<int>(z.size()))
- {
- z.resize(this->mDimension);
- }
- return LCPSolverShared<Real>::Solve(q.data(), M.data(), w.data(), z.data(), result);
- }
- private:
- std::vector<typename LCPSolverShared<Real>::Variable> mVectorVarBasic;
- std::vector<typename LCPSolverShared<Real>::Variable> mVectorVarNonbasic;
- std::vector<Real> mVectorAugmented;
- std::vector<Real> mVectorQMin;
- std::vector<Real> mVectorMinRatio;
- std::vector<Real> mVectorRatio;
- std::vector<Real*> mVectorPoly;
- };
- }
|