- Move existing OndselSolver, GNN ML layer, and tooling into GNN/ directory for integration in later phases - Add Create addon scaffold: package.xml, Init.py - Add expression DAG with eval, symbolic diff, simplification - Add parameter table with fixed/free variable tracking - Add quaternion rotation as polynomial Expr trees - Add RigidBody entity (7 DOF: position + unit quaternion) - Add constraint classes: Coincident, DistancePointPoint, Fixed - Add Newton-Raphson solver with symbolic Jacobian + numpy lstsq - Add pre-solve passes: substitution + single-equation - Add DOF counting via Jacobian SVD rank - Add KindredSolver IKCSolver bridge for kcsolve integration - Add 82 unit tests covering all modules Registers as 'kindred' solver via kcsolve.register_solver() when loaded by Create's addon_loader.
243 lines
6.8 KiB
C++
243 lines
6.8 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2023 Ondsel, Inc. *
|
|
* *
|
|
* This file is part of OndselSolver. *
|
|
* *
|
|
* See LICENSE file for details about copyright. *
|
|
***************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <ostream>
|
|
|
|
#include "Array.h"
|
|
#include "SimulationStoppingError.h"
|
|
|
|
namespace MbD {
|
|
template<typename T>
|
|
class FullVector : public Array<T>
|
|
{
|
|
public:
|
|
FullVector() : Array<T>() {}
|
|
FullVector(std::vector<T> vec) : Array<T>(vec) {}
|
|
FullVector(size_t count) : Array<T>(count) {}
|
|
FullVector(size_t count, const T& value) : Array<T>(count, value) {}
|
|
FullVector(typename std::vector<T>::iterator begin, typename std::vector<T>::iterator end) : Array<T>(begin, end) {}
|
|
FullVector(std::initializer_list<T> list) : Array<T>{ list } {}
|
|
double dot(std::shared_ptr<FullVector<T>> vec);
|
|
void atiplusNumber(size_t i, T value);
|
|
void atiminusNumber(size_t i, T value);
|
|
double sumOfSquares() override;
|
|
size_t numberOfElements() override;
|
|
void zeroSelf() override;
|
|
void atiplusFullVector(size_t i, std::shared_ptr<FullVector<T>> fullVec);
|
|
void atiplusFullVectortimes(size_t i, std::shared_ptr<FullVector<T>> fullVec, T factor);
|
|
void equalSelfPlusFullVectortimes(std::shared_ptr<FullVector<T>> fullVec, T factor);
|
|
double maxMagnitude() override;
|
|
void normalizeSelf();
|
|
double length();
|
|
virtual void conditionSelf();
|
|
virtual void conditionSelfWithTol(double tol);
|
|
std::shared_ptr<FullVector<T>> clonesptr();
|
|
bool isIncreasing();
|
|
bool isIncreasingIfExceptionsAreLessThan(double tol);
|
|
bool isDecreasingIfExceptionsAreLessThan(double tol);
|
|
|
|
|
|
std::ostream& printOn(std::ostream& s) const override;
|
|
|
|
};
|
|
template<typename T>
|
|
inline double FullVector<T>::dot(std::shared_ptr<FullVector<T>> vec)
|
|
{
|
|
auto n = this->size();
|
|
double answer = 0.0;
|
|
for (size_t i = 0; i < n; i++) {
|
|
answer += this->at(i) * vec->at(i);
|
|
}
|
|
return answer;
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::atiplusNumber(size_t i, T value)
|
|
{
|
|
this->at(i) += value;
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::atiminusNumber(size_t i, T value)
|
|
{
|
|
this->at(i) -= value;
|
|
}
|
|
template<>
|
|
inline double FullVector<double>::sumOfSquares()
|
|
{
|
|
double sum = 0.0;
|
|
for (size_t i = 0; i < this->size(); i++)
|
|
{
|
|
double element = this->at(i);
|
|
sum += element * element;
|
|
}
|
|
return sum;
|
|
}
|
|
template<typename T>
|
|
inline double FullVector<T>::sumOfSquares()
|
|
{
|
|
throw SimulationStoppingError("To be implemented.");
|
|
return 0.0;
|
|
}
|
|
template<typename T>
|
|
inline size_t FullVector<T>::numberOfElements()
|
|
{
|
|
return this->size();
|
|
}
|
|
template<>
|
|
inline void FullVector<double>::zeroSelf()
|
|
{
|
|
for (size_t i = 0; i < this->size(); i++) {
|
|
this->at(i) = 0.0;
|
|
}
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::zeroSelf()
|
|
{
|
|
throw SimulationStoppingError("To be implemented.");
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::atiplusFullVector(size_t i1, std::shared_ptr<FullVector<T>> fullVec)
|
|
{
|
|
for (size_t ii = 0; ii < fullVec->size(); ii++)
|
|
{
|
|
auto i = i1 + ii;
|
|
this->at(i) += fullVec->at(ii);
|
|
}
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::atiplusFullVectortimes(size_t i1, std::shared_ptr<FullVector<T>> fullVec, T factor)
|
|
{
|
|
for (size_t ii = 0; ii < fullVec->size(); ii++)
|
|
{
|
|
auto i = i1 + ii;
|
|
this->at(i) += fullVec->at(ii) * factor;
|
|
}
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::equalSelfPlusFullVectortimes(std::shared_ptr<FullVector<T>> fullVec, T factor)
|
|
{
|
|
for (size_t i = 0; i < this->size(); i++)
|
|
{
|
|
this->atiplusNumber(i, fullVec->at(i) * factor);
|
|
}
|
|
}
|
|
template<>
|
|
inline double FullVector<double>::maxMagnitude()
|
|
{
|
|
double max = 0.0;
|
|
for (size_t i = 0; i < this->size(); i++)
|
|
{
|
|
double element = this->at(i);
|
|
if (element < 0.0) element = -element;
|
|
if (max < element) max = element;
|
|
}
|
|
return max;
|
|
}
|
|
template<typename T>
|
|
inline double FullVector<T>::maxMagnitude()
|
|
{
|
|
throw SimulationStoppingError("To be implemented.");
|
|
return 0.0;
|
|
}
|
|
template<>
|
|
inline void FullVector<double>::normalizeSelf()
|
|
{
|
|
double length = this->length();
|
|
if (length == 0.0) throw std::runtime_error("Cannot normalize a null vector.");
|
|
this->magnifySelf(1.0 / length);
|
|
}
|
|
template<typename T>
|
|
inline double FullVector<T>::length()
|
|
{
|
|
double ssq = 0.0;
|
|
for (size_t i = 0; i < this->size(); i++)
|
|
{
|
|
double elem = this->at(i);
|
|
ssq += elem * elem;
|
|
}
|
|
return std::sqrt(ssq);
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::conditionSelf()
|
|
{
|
|
constexpr double epsilon = std::numeric_limits<double>::epsilon();
|
|
double tol = this->maxMagnitude() * epsilon;
|
|
this->conditionSelfWithTol(tol);
|
|
}
|
|
template<>
|
|
inline void FullVector<double>::conditionSelfWithTol(double tol)
|
|
{
|
|
for (size_t i = 0; i < this->size(); i++)
|
|
{
|
|
double element = this->at(i);
|
|
if (element < 0.0) element = -element;
|
|
if (element < tol) this->atiput(i, 0.0);
|
|
}
|
|
}
|
|
template<typename T>
|
|
inline void FullVector<T>::conditionSelfWithTol([[maybe_unused]] double tol)
|
|
{
|
|
assert(false && tol != tol); // clang++ flips out with warnings if you don't use 'tol'
|
|
// but suppressing that warning breaks Visual Studio.
|
|
return; // Visual Studio demands the unused return
|
|
}
|
|
template<typename T>
|
|
inline std::shared_ptr<FullVector<T>> FullVector<T>::clonesptr()
|
|
{
|
|
//Return shallow copy of *this wrapped in shared_ptr
|
|
throw SimulationStoppingError("To be implemented.");
|
|
return std::make_shared<FullVector<T>>(*this);
|
|
}
|
|
template<typename T>
|
|
inline bool FullVector<T>::isIncreasing()
|
|
{
|
|
return isIncreasingIfExceptionsAreLessThan(0.0);
|
|
}
|
|
template<typename T>
|
|
inline bool FullVector<T>::isIncreasingIfExceptionsAreLessThan(double tol)
|
|
{
|
|
//"Test if elements are increasing."
|
|
//"Ok if spoilers are less than tol."
|
|
auto next = this->at(0);
|
|
for (size_t i = 1; i < this->size(); i++)
|
|
{
|
|
auto previous = next;
|
|
next = this->at(i);
|
|
if (previous > next && (previous - tol > next)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
template<typename T>
|
|
inline bool FullVector<T>::isDecreasingIfExceptionsAreLessThan(double tol)
|
|
{
|
|
//"Test if elements are increasing."
|
|
//"Ok if spoilers are less than tol."
|
|
auto next = this->at(0);
|
|
for (size_t i = 1; i < this->size(); i++)
|
|
{
|
|
auto previous = next;
|
|
next = this->at(i);
|
|
if (previous < next && (previous + tol < next)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
template<typename T>
|
|
inline std::ostream& FullVector<T>::printOn(std::ostream& s) const
|
|
{
|
|
s << "FullVec{";
|
|
s << this->at(0);
|
|
for (size_t i = 1; i < this->size(); i++)
|
|
{
|
|
s << ", " << this->at(i);
|
|
}
|
|
s << "}";
|
|
return s;
|
|
}
|
|
}
|