LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_geometry_support.cpp
浏览该文件的文档.
1#include <stdexcept>
6
7#include <algorithm>
8#include <cmath>
9#include <utility>
10
11namespace LMCAS::geometry_detail {
12
14 const std::vector<std::shared_ptr<SymbolicExpr>>& vector,
15 const std::string& name,
16 const std::string& operation)
17{
18 for (size_t i = 0; i < vector.size(); ++i) {
19 if (!vector[i] || !LMCAS::detail::node(vector[i])) {
22 name + " contains a null component at index " + std::to_string(i),
23 operation);
24 }
25 }
26 return Result<void>::success();
27}
28
30 const std::vector<std::shared_ptr<SymbolicExpr>>& a,
31 const std::vector<std::shared_ptr<SymbolicExpr>>& b,
33 const std::string& operation)
34{
35 auto step = context.consume_steps(1, operation);
36 if (!step) return step;
37 if (a.empty() || b.empty()) {
39 CasErrc::InvalidArgument, "vectors cannot be empty", operation);
40 }
41 if (a.size() != b.size()) {
43 CasErrc::InvalidArgument, "vector dimensions do not match", operation);
44 }
45 auto a_check = validate_symbolic_vector(a, "left vector", operation);
46 if (!a_check) return a_check;
47 return validate_symbolic_vector(b, "right vector", operation);
48}
49
51 const SurfaceSymbolic& surf,
52 const std::vector<std::shared_ptr<SymbolicExpr>>& point,
54 const std::string& operation)
55{
56 auto step = context.consume_steps(1, operation);
57 if (!step) return step;
58 if (!surf.F || !LMCAS::detail::node(surf.F)) {
60 CasErrc::InvalidArgument, "surface equation cannot be null", operation);
61 }
62 if (surf.vars.empty()) {
64 CasErrc::InvalidArgument, "surface variables cannot be empty", operation);
65 }
66 if (surf.vars.size() != point.size()) {
69 "surface variable count must match point dimension",
70 operation);
71 }
72 for (const auto& var : surf.vars) {
73 if (var.empty()) {
75 CasErrc::InvalidArgument, "surface variable names cannot be empty",
76 operation);
77 }
78 }
79 return validate_symbolic_vector(point, "surface point", operation);
80}
81
83 const std::shared_ptr<SymbolicExpr>& expr,
84 const std::string& operation,
85 const std::string& message, ComputationContext& context)
86try {
87
88 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
89 (context).limits().max_ast_nodes, "transform");
90 if (!expr || !LMCAS::detail::node(expr)) {
91 return ExpressionResult::failure(CasErrc::Inconclusive, message, operation);
92 }
93 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(expr), transform_budget));
94 if (!simplified || !LMCAS::detail::node(simplified)) {
95 return ExpressionResult::failure(CasErrc::Inconclusive, message, operation);
96 }
97 return ExpressionResult::success(std::move(simplified));
98} catch (const CasError& error) {
99 return ExpressionResult::failure(error);
100} catch (const std::bad_alloc&) {
101 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
102} catch (const std::length_error& error) {
103 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
104} catch (const std::exception& error) {
105 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), operation);
106}
107
109 const std::vector<std::shared_ptr<SymbolicExpr>>& expressions,
111 const std::string& operation,
112 std::vector<double>* values)
113{
114 double max_abs = 0.0;
115 if (values) {
116 values->clear();
117 values->reserve(expressions.size());
118 }
119 for (const auto& expression : expressions) {
120 if (!expression || !LMCAS::detail::node(expression)) {
123 "numeric vector contains a null expression",
124 operation);
125 }
126 auto evaluated = evaluate_numeric(
127 *expression, NumericBindings{}, context);
128 if (!evaluated) {
129 if (evaluated.error().code == CasErrc::Cancelled ||
130 evaluated.error().code == CasErrc::ResourceLimit) {
131 return Result<double>::failure(evaluated.error());
132 }
135 "vector is not finite numeric in the supported domain",
136 operation);
137 }
138 if (!evaluated.value().is_finite() ||
139 !std::isfinite(evaluated.value().value)) {
142 "vector is not finite numeric in the supported domain",
143 operation);
144 }
145 max_abs = std::max(max_abs, std::abs(evaluated.value().value));
146 if (values) {
147 values->push_back(evaluated.value().value);
148 }
149 }
150 return Result<double>::success(max_abs);
151}
152
154 const std::vector<std::shared_ptr<SymbolicExpr>>& expressions,
156 const std::string& operation,
157 const std::string& domain_message,
158 const std::string& inconclusive_message)
159{
160 auto scaled = numeric_vector_scale_checked(
161 expressions, context, operation);
162 if (!scaled) {
163 if (scaled.error().code == CasErrc::Cancelled ||
164 scaled.error().code == CasErrc::ResourceLimit) {
165 return Result<void>::failure(scaled.error());
166 }
168 CasErrc::Inconclusive, inconclusive_message, operation);
169 }
170 if (scaled.value() == 0.0) {
172 CasErrc::DomainError, domain_message, operation);
173 }
174 return Result<void>::success();
175}
176
178 const std::shared_ptr<SymbolicExpr>& expr,
180 const std::string& operation,
181 const std::string& domain_message,
182 const std::string& inconclusive_message)
183try {
184 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
185 (context).limits().max_ast_nodes, "transform");
186 if (!expr || !LMCAS::detail::node(expr)) {
188 inconclusive_message, operation);
189 }
190 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(expr), transform_budget));
191 if (!simplified || !LMCAS::detail::node(simplified)) {
193 inconclusive_message, operation);
194 }
195 if (simplified->is_zero()) {
197 domain_message, operation);
198 }
199 auto numeric = evaluate_numeric(*simplified, NumericBindings{}, context);
200 if (!numeric) {
201 if (numeric.error().code == CasErrc::Cancelled ||
202 numeric.error().code == CasErrc::ResourceLimit) {
203 return Result<void>::failure(numeric.error());
204 }
206 inconclusive_message, operation);
207 }
208 if (!numeric.value().is_finite() ||
209 !std::isfinite(numeric.value().value)) {
211 inconclusive_message, operation);
212 }
213 if (numeric.value().value == 0.0) {
215 domain_message, operation);
216 }
217 return Result<void>::success();
218} catch (const CasError& error) {
219 return Result<void>::failure(error);
220} catch (const std::bad_alloc&) {
221 return Result<void>::failure(CasErrc::ResourceLimit, "allocation failed", operation);
222} catch (const std::length_error& error) {
223 return Result<void>::failure(CasErrc::ResourceLimit, error.what(), operation);
224} catch (const std::exception& error) {
225 return Result<void>::failure(CasErrc::InternalInvariant, error.what(), operation);
226}
227
230 const std::string& operation)
231{
232 auto valid = validate_same_dimension_vectors(line.point, line.direction,
233 context, operation);
234 if (!valid) return valid;
235 if (line.point.size() != 3) {
237 "line geometry requires 3-dimensional data",
238 operation);
239 }
241 line.direction, context, operation,
242 "line direction cannot be zero",
243 "line direction nonzero condition cannot be verified");
244}
245
248 const std::string& operation)
249{
250 if (!plane.d || !LMCAS::detail::node(plane.d)) {
252 "plane constant cannot be null",
253 operation);
254 }
255 if (plane.normal.size() != 3) {
257 "plane geometry requires a 3-dimensional normal",
258 operation);
259 }
260 auto normal_valid = validate_symbolic_vector(plane.normal, "plane normal",
261 operation);
262 if (!normal_valid) return normal_valid;
264 plane.normal, context, operation,
265 "plane normal cannot be zero",
266 "plane normal nonzero condition cannot be verified");
267}
268
269}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, 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)
Result< void > validate_plane_checked(const PlaneSymbolic &plane, ComputationContext &context, const std::string &operation)
ExpressionResult simplify_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &operation, const std::string &message, ComputationContext &context)
Result< void > validate_symbolic_vector(const std::vector< std::shared_ptr< SymbolicExpr > > &vector, const std::string &name, const std::string &operation)
Result< void > validate_surface_point(const SurfaceSymbolic &surf, const std::vector< std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context, const std::string &operation)
Result< void > validate_line_checked(const LineSymbolic &line, ComputationContext &context, const std::string &operation)
Result< void > checked_nonzero_numeric_or_exact(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context, const std::string &operation, const std::string &domain_message, const std::string &inconclusive_message)
Result< void > validate_same_dimension_vectors(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context, const std::string &operation)
Result< void > checked_nonzero_numeric_vector(const std::vector< std::shared_ptr< SymbolicExpr > > &expressions, ComputationContext &context, const std::string &operation, const std::string &domain_message, const std::string &inconclusive_message)
const std::string const LimitExprPtr & point
const PlaneSymbolic & plane
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const MultiPoly & b
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::vector< std::shared_ptr< SymbolicExpr > > point
直线上一点。
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
std::vector< std::shared_ptr< SymbolicExpr > > normal
法向量。
NumberDomainSet expressions()
std::vector< std::shared_ptr< SymbolicExpr > > direction
方向向量。
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
std::shared_ptr< SymbolicExpr > F
曲面方程左端,等于零。
std::unordered_map< std::string, double > NumericBindings
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
std::shared_ptr< SymbolicExpr > d
常数项。
std::vector< std::string > vars
坐标变量名 {x,y,z}。
由一点和方向向量定义的符号直线。
由法向量和常数 d 定义的符号平面 ax + by + cz = d。
内部 AST 定义。