Wildmeshing Toolkit
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>
7 #include <wmtk/utils/Logger.hpp>
8 
9 #include <polysolve/nonlinear/Solver.hpp>
10 
11 #include <Eigen/Core>
12 
13 namespace wmtk::operations {
14 
15 namespace {
16 template <typename T>
17 const Eigen::Matrix<T, -1, 1> convert(const polysolve::nonlinear::Problem::TVector& v)
18 {
19  return v;
20 }
21 
22 template <>
23 const 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 
34 template <typename T>
35 class OptimizationSmoothing::WMTKProblem : public polysolve::nonlinear::Problem
36 {
37 public:
38  using typename polysolve::nonlinear::Problem::Scalar;
39  using typename polysolve::nonlinear::Problem::THessian;
40  using typename polysolve::nonlinear::Problem::TVector;
41 
43  attribute::Accessor<T>&& handle,
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 
62 private:
66 
68 };
69 
70 template <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 
82 template <typename T>
83 Eigen::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 
97 template <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 
109 template <typename T>
110 void 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 
119 template <typename T>
120 void 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 
129 template <typename T>
131 {
132  // m_accessor.vector_attribute(m_simplex.tuple()) = new_x;
133 }
134 
135 template <typename T>
136 bool 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 
158 OptimizationSmoothing::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 
165  create_solver();
166 }
167 
169 {
170  m_solver = polysolve::nonlinear::Solver::create(
173  1,
174  opt_logger());
175 }
176 
177 
178 std::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
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:25
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
Definition: Operation.hpp:101
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
Definition: autodiff.h:995
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