LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_geometry_surface.cpp
浏览该文件的文档.
6
7#include <algorithm>
8#include <cmath>
9#include <limits>
10#include <stdexcept>
11#include <utility>
12
13namespace LMCAS {
14using namespace geometry_detail;
15
16namespace {
17
19 const std::shared_ptr<SymbolicExpr>& expr,
20 const std::string& var,
21 const std::string& operation, ComputationContext& context)
22try {
23
24 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
25 (context).limits().max_ast_nodes, "transform");
26 try {
27 auto derivative = detail::make_expression_ptr(detail::differentiate_node(detail::node(expr), var, transform_budget));
28 return simplify_checked(
29 derivative, operation,
30 "surface derivative is outside the supported domain", context);
31 } catch (const std::length_error& error) { return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), operation); } catch (const std::exception&) {
34 "surface derivative is outside the supported domain",
35 operation);
36 }
37} catch (const CasError& error) {
38 return ExpressionResult::failure(error);
39} catch (const std::bad_alloc&) {
40 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
41} catch (const std::length_error& error) {
42 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
43} catch (const std::exception& error) {
44 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), operation);
45}
46
48 const SurfaceSymbolic& surf,
49 const std::vector<std::shared_ptr<SymbolicExpr>>& point,
50 const std::string& operation, ComputationContext& context)
51try {
52
53 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
54 (context).limits().max_ast_nodes, "transform");
55 std::vector<std::shared_ptr<SymbolicExpr>> gradient;
56 gradient.reserve(surf.vars.size());
57 for (size_t i = 0; i < surf.vars.size(); ++i) {
58 auto derivative = differentiate_surface_checked(surf.F, surf.vars[i], operation, context);
59 if (!derivative) return VectorExprListResult::failure(derivative.error());
60 auto substituted = derivative.value();
61 for (size_t j = 0; j < surf.vars.size(); ++j) {
62 substituted = detail::make_expression_ptr(detail::substitute_node(detail::node(substituted), surf.vars[j], detail::node(point[j]), transform_budget));
63 if (!substituted || !LMCAS::detail::node(substituted)) {
66 "surface derivative substitution is outside the supported domain",
67 operation);
68 }
69 }
70 auto simplified = simplify_checked(
71 substituted, operation,
72 "surface derivative substitution is outside the supported domain", context);
73 if (!simplified) return VectorExprListResult::failure(simplified.error());
74 gradient.push_back(std::move(simplified.value()));
75 }
76 return VectorExprListResult::success(std::move(gradient));
77} catch (const CasError& error) {
79} catch (const std::bad_alloc&) {
80 return VectorExprListResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
81} catch (const std::length_error& error) {
82 return VectorExprListResult::failure(CasErrc::ResourceLimit, error.what(), operation);
83} catch (const std::exception& error) {
84 return VectorExprListResult::failure(CasErrc::InternalInvariant, error.what(), operation);
85}
86
88 const std::vector<std::shared_ptr<SymbolicExpr>>& gradient,
90 const std::string& operation,
91 std::vector<double>& values,
92 const std::string& singular_message)
93{
94 auto scaled = numeric_vector_scale_checked(
95 gradient, context, operation, &values);
96 if (!scaled) {
97 if (scaled.error().code == CasErrc::Cancelled ||
98 scaled.error().code == CasErrc::ResourceLimit) {
99 return Result<double>::failure(scaled.error());
100 }
103 "surface gradient nonzero condition cannot be verified",
104 operation);
105 }
106 if (scaled.value() == 0.0) {
108 CasErrc::DomainError, singular_message, operation);
109 }
110 return scaled;
111}
112
114 const std::vector<double>& gradient_values,
115 double gradient_scale,
116 const std::vector<double>& point_values,
117 double point_scale,
118 const std::string& operation)
119{
120 double normalized_dot = 0.0;
121 for (size_t i = 0; i < point_values.size(); ++i) {
122 normalized_dot = std::fma(
123 gradient_values[i] / gradient_scale,
124 point_values[i] / point_scale,
125 normalized_dot);
126 }
127 const double plane_constant = normalized_dot * point_scale;
128 if (!std::isfinite(plane_constant)) {
131 "tangent plane constant is outside the supported domain",
132 operation);
133 }
134
136 plane.normal.reserve(gradient_values.size());
137 for (double component : gradient_values) {
138 plane.normal.push_back(
139 SymbolicExpr::number(component / gradient_scale));
140 }
141 plane.d = SymbolicExpr::number(plane_constant);
142 return PlaneSymbolicResult::success(std::move(plane));
143}
144
145}
146
148 const SurfaceSymbolic& surf,
149 const std::vector<std::shared_ptr<SymbolicExpr>>& point,
151 const std::string operation = "surface_normal";
152 auto valid = validate_surface_point(surf, point, context, operation);
153 if (!valid) return VectorExprListResult::failure(valid.error());
154 auto step = context.consume_steps(surf.vars.size() * 4 + 4, operation);
155 if (!step) return VectorExprListResult::failure(step.error());
156
157 auto gradient = surface_gradient_at_point_checked(surf, point, operation, context);
158 if (!gradient) return gradient;
159 std::vector<double> gradient_values;
160 auto scaled = surface_gradient_scale_checked(
161 gradient.value(), context, operation, gradient_values,
162 "surface normal is undefined at a singular point");
163 if (!scaled) return VectorExprListResult::failure(scaled.error());
164
165 double scaled_norm_sq = 0.0;
166 for (double component : gradient_values) {
167 const double ratio = component / scaled.value();
168 scaled_norm_sq += ratio * ratio;
169 }
170 const double scaled_norm = std::sqrt(scaled_norm_sq);
171
172 std::vector<std::shared_ptr<SymbolicExpr>> result;
173 result.reserve(gradient_values.size());
174 for (double component : gradient_values) {
175 result.push_back(SymbolicExpr::number(
176 (component / scaled.value()) / scaled_norm));
177 }
178 return VectorExprListResult::success(std::move(result));
179}
180
182 const SurfaceSymbolic& surf,
183 const std::vector<std::shared_ptr<SymbolicExpr>>& point) {
185 return surface_normal_checked(surf, point, context);
186}
187
188
190 const SurfaceSymbolic& surf,
191 const std::vector<std::shared_ptr<SymbolicExpr>>& point,
193 const std::string operation = "tangent_plane";
194 auto valid = validate_surface_point(surf, point, context, operation);
195 if (!valid) {
196 return PlaneSymbolicResult::failure(valid.error());
197 }
198 auto step = context.consume_steps(surf.vars.size() * 4 + 4, operation);
199 if (!step) {
200 return PlaneSymbolicResult::failure(step.error());
201 }
202
203 auto gradient = surface_gradient_at_point_checked(surf, point, operation, context);
204 if (!gradient) {
206 }
207 std::vector<double> gradient_values;
208 auto scaled = surface_gradient_scale_checked(
209 gradient.value(), context, operation, gradient_values,
210 "tangent plane is undefined at a singular point");
211 if (!scaled) {
212 return PlaneSymbolicResult::failure(scaled.error());
213 }
214
215 std::vector<double> point_values;
216 auto point_scale = numeric_vector_scale_checked(
217 point, context, operation, &point_values);
218 if (!point_scale &&
219 (point_scale.error().code == CasErrc::Cancelled ||
220 point_scale.error().code == CasErrc::ResourceLimit)) {
221 return PlaneSymbolicResult::failure(point_scale.error());
222 }
223 if (point_scale && point_scale.value() != 0.0 &&
224 scaled.value() >
225 std::numeric_limits<double>::max() /
226 point_scale.value() /
227 static_cast<double>(point.size())) {
228 return scaled_tangent_plane(
229 gradient_values, scaled.value(), point_values,
230 point_scale.value(), operation);
231 }
232
233 auto dot = vector_dot_checked(gradient.value(), point, context);
234 if (!dot) {
235 return PlaneSymbolicResult::failure(dot.error());
236 }
237 auto d = simplify_checked(
238 dot.value(), operation,
239 "tangent plane constant is outside the supported domain", context);
240 if (!d) {
241 return PlaneSymbolicResult::failure(d.error());
242 }
243
245 plane.normal = std::move(gradient.value());
246 plane.d = std::move(d.value());
247 return PlaneSymbolicResult::success(std::move(plane));
248}
249
251 const SurfaceSymbolic& surf,
252 const std::vector<std::shared_ptr<SymbolicExpr>>& point) {
254 return tangent_plane_checked(surf, point, context);
255}
256
257}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::vector< std::shared_ptr< SymbolicExpr > > value)
VectorExprListResult surface_gradient_at_point_checked(const SurfaceSymbolic &surf, const std::vector< std::shared_ptr< SymbolicExpr > > &point, const std::string &operation, ComputationContext &context)
Result< double > surface_gradient_scale_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &gradient, ComputationContext &context, const std::string &operation, std::vector< double > &values, const std::string &singular_message)
ExpressionResult differentiate_surface_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const std::string &operation, ComputationContext &context)
PlaneSymbolicResult scaled_tangent_plane(const std::vector< double > &gradient_values, double gradient_scale, const std::vector< double > &point_values, double point_scale, const std::string &operation)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< double > numeric_vector_scale_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &expressions, ComputationContext &context, const std::string &operation, std::vector< double > *values=nullptr)
ExpressionResult simplify_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &operation, const std::string &message, ComputationContext &context)
Result< void > validate_surface_point(const SurfaceSymbolic &surf, const std::vector< std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context, const std::string &operation)
const std::string const LimitExprPtr & point
const PlaneSymbolic & plane
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
Result< PlaneSymbolic > PlaneSymbolicResult
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
VectorExprListResult surface_normal_checked(const SurfaceSymbolic &surf, const std::vector< std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context)
PlaneSymbolicResult tangent_plane_checked(const SurfaceSymbolic &surf, const std::vector< std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > normal
法向量。
Result< std::vector< std::shared_ptr< SymbolicExpr > > > VectorExprListResult
std::shared_ptr< SymbolicExpr > F
曲面方程左端,等于零。
VectorField gradient(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars)
ExpressionResult vector_dot_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
std::shared_ptr< SymbolicExpr > d
常数项。
std::vector< std::string > vars
坐标变量名 {x,y,z}。
由法向量和常数 d 定义的符号平面 ax + by + cz = d。
内部 AST 定义。