Wildmeshing Toolkit
Loading...
Searching...
No Matches
OptimizationSmoothing.cpp
Go to the documentation of this file.
2
3#include <polysolve/nonlinear/Problem.hpp>
4#include <wmtk/Mesh.hpp>
5#include <wmtk/Types.hpp>
8
9#include <polysolve/nonlinear/Solver.hpp>
10
11#include <Eigen/Core>
12
13namespace wmtk::operations {
14
15namespace {
16template <typename T>
17const Eigen::Matrix<T, -1, 1> convert(const polysolve::nonlinear::Problem::TVector& v)
18{
19 return v;
20}
21
22template <>
23const Eigen::Matrix<Rational, -1, 1> convert(const polysolve::nonlinear::Problem::TVector& v)
24{
25 Eigen::Matrix<Rational, -1, 1> res(v.size());
26 for (int64_t d = 0; d < v.size(); ++d) {
27 res[d] = Rational(v[d], true);
28 }
29 return res;
30}
31} // namespace
32
33
34template <typename T>
35class OptimizationSmoothing::WMTKProblem : public polysolve::nonlinear::Problem
36{
37public:
38 using typename polysolve::nonlinear::Problem::Scalar;
39 using typename polysolve::nonlinear::Problem::THessian;
40 using typename polysolve::nonlinear::Problem::TVector;
41
44 const simplex::Simplex& simplex,
46 const wmtk::function::Function& energy);
47
48 TVector initial_value() const;
49
50 double value(const TVector& x) override;
51 void gradient(const TVector& x, TVector& gradv) override;
52 void hessian(const TVector& x, THessian& hessian) override
53 {
54 throw std::runtime_error("Sparse functions do not exist, use dense solver");
55 }
56 void hessian(const TVector& x, Eigen::MatrixXd& hessian) override;
57
58 void solution_changed(const TVector& new_x) override;
59
60 bool is_step_valid(const TVector& x0, const TVector& x1) override;
61
62private:
66
68};
69
70template <typename T>
72 attribute::Accessor<T>&& accessor,
73 const simplex::Simplex& simplex,
75 const wmtk::function::Function& energy)
76 : m_accessor(std::move(accessor))
77 , m_simplex(simplex)
78 , m_energy(energy)
79 , m_invariants(invariants)
80{}
81
82template <typename T>
83Eigen::Matrix<double, -1, 1> OptimizationSmoothing::WMTKProblem<T>::initial_value() const
84{
85 if constexpr (std::is_same_v<T, Rational>) {
86 const Eigen::Matrix<T, -1, 1> tmp = m_accessor.const_vector_attribute(m_simplex.tuple());
87 Eigen::Matrix<double, -1, 1> tmp1(tmp.size());
88 for (int64_t d = 0; d < tmp1.size(); ++d) {
89 tmp1[d] = tmp[d].to_double();
90 }
91 return tmp1;
92 } else {
93 return m_accessor.const_vector_attribute(m_simplex.tuple());
94 }
95}
96
97template <typename T>
99{
100 auto tmp = m_accessor.vector_attribute(m_simplex.tuple());
101 m_accessor.vector_attribute(m_simplex.tuple()) = convert<T>(x);
102 double res = m_energy.get_value(m_simplex);
103
104 m_accessor.vector_attribute(m_simplex.tuple()) = tmp;
105
106 return res;
107}
108
109template <typename T>
110void OptimizationSmoothing::WMTKProblem<T>::gradient(const TVector& x, TVector& gradv)
111{
112 auto tmp = m_accessor.vector_attribute(m_simplex.tuple());
113 m_accessor.vector_attribute(m_simplex.tuple()) = convert<T>(x);
114 gradv = m_energy.get_gradient(m_simplex);
115
116 m_accessor.vector_attribute(m_simplex.tuple()) = tmp;
117}
118
119template <typename T>
120void OptimizationSmoothing::WMTKProblem<T>::hessian(const TVector& x, Eigen::MatrixXd& hessian)
121{
122 auto tmp = m_accessor.vector_attribute(m_simplex.tuple());
123 m_accessor.vector_attribute(m_simplex.tuple()) = convert<T>(x);
124 hessian = m_energy.get_hessian(m_simplex);
125
126 m_accessor.vector_attribute(m_simplex.tuple()) = tmp;
127}
128
129template <typename T>
131{
132 // m_accessor.vector_attribute(m_simplex.tuple()) = new_x;
133}
134
135template <typename T>
136bool OptimizationSmoothing::WMTKProblem<T>::is_step_valid(const TVector& x0, const TVector& x1)
137{
138 auto tmp = m_accessor.vector_attribute(m_simplex.tuple());
139 m_accessor.vector_attribute(m_simplex.tuple()) = convert<T>(x1);
140
141 auto domain = m_energy.domain(m_simplex);
142 std::vector<Tuple> dom_tmp;
143 dom_tmp.reserve(domain.size());
144 std::transform(
145 domain.begin(),
146 domain.end(),
147 std::back_inserter(dom_tmp),
148 [](const simplex::Simplex& s) { return s.tuple(); });
149
150 bool res = m_invariants.after({}, dom_tmp);
151
152 m_accessor.vector_attribute(m_simplex.tuple()) = tmp;
153
154 return res;
155}
156
157
158OptimizationSmoothing::OptimizationSmoothing(std::shared_ptr<wmtk::function::Function> energy)
159 : AttributesUpdate(energy->mesh())
160 , m_energy(energy)
161{
162 m_linear_solver_params = R"({"solver": "Eigen::LDLT"})"_json;
163 m_nonlinear_solver_params = R"({"solver": "DenseNewton", "max_iterations": 10})"_json;
164
166}
167
169{
170 m_solver = polysolve::nonlinear::Solver::create(
173 1,
174 opt_logger());
175}
176
177
178std::vector<simplex::Simplex> OptimizationSmoothing::execute(const simplex::Simplex& simplex)
179{
180 if (m_energy->attribute_handle().holds<double>()) {
181 auto accessor = mesh().create_accessor(m_energy->attribute_handle().as<double>());
182 WMTKProblem problem(std::move(accessor), simplex, m_invariants, *m_energy);
183
184 auto x = problem.initial_value();
185 try {
186 m_solver->minimize(problem, x);
187
188 accessor.vector_attribute(simplex.tuple()) = x;
189
190 } catch (const std::exception&) {
191 return {};
192 }
193
194
195 return AttributesUpdate::execute(simplex);
196 } else {
197 assert(m_energy->attribute_handle().holds<Rational>());
198 auto accessor = mesh().create_accessor(m_energy->attribute_handle().as<Rational>());
199 WMTKProblem problem(std::move(accessor), simplex, m_invariants, *m_energy);
200
201 auto x = problem.initial_value();
202 try {
203 m_solver->minimize(problem, x);
204
205 for (int64_t d = 0; d < m_energy->attribute_handle().dimension(); ++d) {
206 accessor.vector_attribute(simplex.tuple())[d] = Rational(x[d], true);
207 }
208 } catch (const std::exception&) {
209 return {};
210 }
211
212
213 return AttributesUpdate::execute(simplex);
214 }
215}
216
217} // namespace wmtk::operations
wmtk::attribute::Accessor< int64_t > m_accessor
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
A CachingAccessor that uses tuples for accessing attributes instead of indices.
Definition Accessor.hpp:28
MapResult< D > vector_attribute(const ArgType &t)
ConstMapResult< D > const_vector_attribute(const ArgType &t) const
bool after(const std::vector< Tuple > &top_dimension_tuples_before, const std::vector< Tuple > &top_dimension_tuples_after) const override
virtual std::vector< simplex::Simplex > execute(const simplex::Simplex &simplex) override
returns an empty vector in case of failure
const Mesh & mesh() const
Definition Operation.hpp:45
invariants::InvariantCollection m_invariants
void gradient(const TVector &x, TVector &gradv) override
void hessian(const TVector &x, THessian &hessian) override
WMTKProblem(attribute::Accessor< T > &&handle, const simplex::Simplex &simplex, invariants::InvariantCollection &invariants, const wmtk::function::Function &energy)
bool is_step_valid(const TVector &x0, const TVector &x1) override
std::shared_ptr< wmtk::function::Function > m_energy
std::shared_ptr< polysolve::nonlinear::Solver > m_solver
std::vector< simplex::Simplex > execute(const simplex::Simplex &simplex) override
returns an empty vector in case of failure
OptimizationSmoothing(std::shared_ptr< wmtk::function::Function > energy)
const Tuple & tuple() const
Definition Simplex.hpp:53
int8_t convert(PrimitiveType from, PrimitiveType to, int8_t source)
Definition convert.hxx:8
spdlog::logger & opt_logger()
Retrieves the logger for the optimization.
Definition Logger.cpp:75