28 double off_diagonal = std::abs(matrix[p][q]);
29 for (
size_t row = 0; row < 3; ++row) {
30 for (
size_t column = row + 1; column < 3; ++column) {
31 const double candidate = std::abs(matrix[row][column]);
32 if (candidate > off_diagonal) {
33 off_diagonal = candidate;
43 double matrix[3][3],
double vectors[3][3],
size_t p,
size_t q)
45 const double angle = 0.5 * std::atan2(
46 2.0 * matrix[p][q], matrix[q][q] - matrix[p][p]);
47 const double cosine = std::cos(angle);
48 const double sine = std::sin(angle);
49 const double pp = matrix[p][p];
50 const double pq = matrix[p][q];
51 const double qq = matrix[q][q];
53 for (
size_t axis = 0; axis < 3; ++axis) {
54 if (axis == p || axis == q)
continue;
55 const double axis_p = matrix[axis][p];
56 const double axis_q = matrix[axis][q];
57 matrix[axis][p] = cosine * axis_p - sine * axis_q;
58 matrix[p][axis] = matrix[axis][p];
59 matrix[axis][q] = sine * axis_p + cosine * axis_q;
60 matrix[q][axis] = matrix[axis][q];
62 matrix[p][p] = cosine * cosine * pp -
63 2.0 * sine * cosine * pq +
65 matrix[q][q] = sine * sine * pp +
66 2.0 * sine * cosine * pq +
71 for (
size_t axis = 0; axis < 3; ++axis) {
72 const double vector_p = vectors[axis][p];
73 const double vector_q = vectors[axis][q];
74 vectors[axis][p] = cosine * vector_p - sine * vector_q;
75 vectors[axis][q] = sine * vector_p + cosine * vector_q;
89 for (
size_t row = 0; row < 3; ++row) {
90 for (
size_t column = 0; column < 3; ++column) {
96 for (
size_t row = 0; row < 3; ++row) {
97 for (
size_t column = 0; column < 3; ++column) {
103 256.0 * std::numeric_limits<double>::epsilon();
105 for (
size_t iteration = 0; iteration < 64; ++iteration) {
111 for (
size_t axis = 0; axis < 3; ++axis) {
112 result.
values[axis] = matrix[axis][axis];
116 result.
values[axis] = 0.0;
123 const std::shared_ptr<SymbolicExpr>& expression,
126 const std::string& message)
129 (
context).limits().max_ast_nodes,
"transform");
131 if (!simplified || !
node(simplified)) {
145 if (!evaluated.value().is_finite() ||
146 !std::isfinite(evaluated.value().value)) {
153}
catch (
const std::bad_alloc&) {
155}
catch (
const std::length_error& error) {
157}
catch (
const std::exception& error) {
162 const std::shared_ptr<SymbolicExpr>& expanded,
168 (
context).limits().max_ast_nodes,
"transform");
170 if (!derivative || !
node(derivative)) {
173 "quadric second derivative is outside the supported domain",
179 "quadric second derivative coefficient cannot be evaluated");
184}
catch (
const std::bad_alloc&) {
186}
catch (
const std::length_error& error) {
188}
catch (
const std::exception& error) {
193 const std::shared_ptr<SymbolicExpr>& expanded,
195 const std::vector<std::string>&
vars,
200 (
context).limits().max_ast_nodes,
"transform");
202 if (!derivative || !
node(derivative)) {
205 "quadric first derivative is outside the supported domain",
208 for (
const auto& coordinate :
vars) {
210 if (!derivative || !
node(derivative)) {
213 "quadric linear coefficient cannot be substituted",
219 "quadric linear coefficient cannot be evaluated");
222}
catch (
const std::bad_alloc&) {
224}
catch (
const std::length_error& error) {
226}
catch (
const std::exception& error) {
231 const std::shared_ptr<SymbolicExpr>& expanded,
232 const std::vector<std::string>&
vars,
235 double quadratic_matrix[3][3],
247 for (
size_t axis = 0; axis < 3; ++axis) {
248 if (!diagonal[axis]) {
249 error = std::move(diagonal[axis].error());
252 if (!linear_coefficients[axis]) {
253 error = std::move(linear_coefficients[axis].error());
257 for (
size_t axis = 0; axis < 3; ++axis) {
258 quadratic_matrix[axis][axis] = diagonal[axis].
value();
259 linear[axis] = linear_coefficients[axis].
value();
265 const std::shared_ptr<SymbolicExpr>& expanded,
266 const std::vector<std::string>&
vars,
269 double quadratic_matrix[3][3],
273 (
context).limits().max_ast_nodes,
"transform");
274 for (
size_t i = 0; i < 3; ++i) {
275 for (
size_t j = i + 1; j < 3; ++j) {
277 if (!mixed || !
node(mixed)) {
280 "quadric mixed derivative is outside the supported domain",
287 "quadric mixed coefficient cannot be evaluated");
289 error = std::move(mixed_value.error());
292 quadratic_matrix[i][j] = mixed_value.value() * 0.5;
293 quadratic_matrix[j][i] = quadratic_matrix[i][j];
301 const double coefficients[3],
303 double linear_tolerance[3],
307 double projection_scale[3] = {0.0, 0.0, 0.0};
308 for (
size_t row = 0; row < 3; ++row) {
309 const double normalized =
311 if (!std::isfinite(normalized)) {
314 "quadric linear part is outside the supported scale",
318 for (
size_t axis = 0; axis < 3; ++axis) {
319 const double term = principal.
vectors[row][axis] * normalized;
320 projection_scale[axis] =
321 std::max(projection_scale[axis], std::abs(term));
322 linear[axis] = std::fma(
323 principal.
vectors[row][axis], normalized, linear[axis]);
326 for (
size_t axis = 0; axis < 3; ++axis) {
327 linear_tolerance[axis] =
328 256.0 * std::numeric_limits<double>::epsilon() *
329 projection_scale[axis];
336 const double linear[3],
337 const double linear_tolerance[3])
339 for (
size_t axis = 0; axis < 3; ++axis) {
340 if (principal.
values[axis] == 0.0 &&
341 std::abs(linear[axis]) > linear_tolerance[axis]) {
349 const std::shared_ptr<SymbolicExpr>& expanded,
350 const std::vector<std::string>&
vars,
355 (
context).limits().max_ast_nodes,
"transform");
356 auto constant = expanded;
357 for (
const auto& coordinate :
vars) {
359 if (!constant || !
node(constant)) {
362 "quadric constant term cannot be substituted",
368 "quadric constant term cannot be evaluated");
371}
catch (
const std::bad_alloc&) {
373}
catch (
const std::length_error& error) {
375}
catch (
const std::exception& error) {
386 const double linear[3],
391 if (!std::isfinite(centered_constant)) {
394 "quadric constant is outside the supported scale",
397 double centered_scale = std::max(1.0, std::abs(centered_constant));
398 for (
size_t axis = 0; axis < 3; ++axis) {
399 if (principal.
values[axis] == 0.0)
continue;
400 const double factor =
401 (linear[axis] / principal.
values[axis]) * 0.25;
402 const double shift = factor * linear[axis];
403 if (!std::isfinite(factor) || !std::isfinite(shift)) {
406 "quadric translation is outside the supported domain",
409 centered_constant = std::fma(
410 -factor, linear[axis], centered_constant);
411 centered_scale = std::max(centered_scale, std::abs(shift));
413 const double zero_tolerance =
414 256.0 * std::numeric_limits<double>::epsilon() * centered_scale;
421 double centered_constant,
422 double zero_tolerance,
425 if (std::abs(centered_constant) <= zero_tolerance) {
428 "rank-two quadric has a degenerate real locus",
431 const bool indefinite = positive == 1 && negative == 1;
432 const bool real_definite =
433 (positive == 2 && centered_constant < -zero_tolerance) ||
434 (negative == 2 && centered_constant > zero_tolerance);
435 if (indefinite || real_definite) {
440 "rank-two quadric has no real cylinder locus",
448 double centered_constant,
449 double zero_tolerance,
452 const bool real_ellipsoid =
453 (positive == 3 && centered_constant < -zero_tolerance) ||
454 (negative == 3 && centered_constant > zero_tolerance);
455 if (!real_ellipsoid) {
458 std::abs(centered_constant) <= zero_tolerance
459 ?
"definite quadric degenerates to a point"
460 :
"definite quadric has no real locus",
463 const double min_value = std::min(
466 const double max_value = std::max(
478 double centered_constant,
479 double zero_tolerance,
483 (principal.
values[0] > 0.0) +
484 (principal.
values[1] > 0.0) +
485 (principal.
values[2] > 0.0);
487 (principal.
values[0] < 0.0) +
488 (principal.
values[1] < 0.0) +
489 (principal.
values[2] < 0.0);
492 positive, negative, centered_constant, zero_tolerance,
operation);
495 if (negative == 0 || positive == 0) {
497 principal, positive, negative, centered_constant,
500 if (std::abs(centered_constant) <= zero_tolerance) {
507 "quadric is outside the currently classified support domain",
514 const double linear[3],
515 const std::shared_ptr<SymbolicExpr>& expanded,
516 const std::vector<std::string>&
vars,
523 principal, linear, constant.value(),
operation);
525 const auto&
value = centered.value();
538 (
context).limits().max_ast_nodes,
"transform");
541 if (!expanded || !
node(expanded)) expanded = surf.
F;
543 double quadratic_matrix[3][3] = {};
544 double linear_coefficients[3];
546 if (!extract_axis_coefficients(
548 linear_coefficients, error)) {
551 if (!extract_mixed_coefficients(
556 const SymmetricEigen3 principal =
557 diagonalize_symmetric_3x3(quadratic_matrix);
558 if (principal.coefficient_scale == 0.0) {
561 "quadric has no nonzero quadratic part",
564 if (principal.unresolved_rank) {
567 "quadric rank is unresolved within the eigensolver error bound",
571 double linear[3] = {0.0, 0.0, 0.0};
572 double linear_tolerance[3];
573 if (!project_linear_coefficients(
574 principal, linear_coefficients, linear, linear_tolerance,
579 (principal.values[0] != 0.0) +
580 (principal.values[1] != 0.0) +
581 (principal.values[2] != 0.0);
584 if (has_null_axis_linear_term(principal, linear, linear_tolerance)) {
589 "rank-one quadric is degenerate or has no real locus",
593 has_null_axis_linear_term(principal, linear, linear_tolerance)) {
596 return classify_translated_quadric(
600}
catch (
const std::bad_alloc&) {
602}
catch (
const std::length_error& error) {
604}
catch (
const std::exception& error) {
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
double largest_off_diagonal(const double matrix[3][3], size_t &p, size_t &q)
VectorStringResult classify_definite_locus(const SymmetricEigen3 &principal, int positive, int negative, double centered_constant, double zero_tolerance, const std::string &operation)
SymmetricEigen3 diagonalize_symmetric_3x3(const double input[3][3])
Result< double > coefficient_of_constant(const std::shared_ptr< SymbolicExpr > &expanded, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
Result< double > finite_numeric_coeff(const std::shared_ptr< SymbolicExpr > &expression, ComputationContext &context, const std::string &operation, const std::string &message)
bool project_linear_coefficients(const SymmetricEigen3 &principal, const double coefficients[3], double linear[3], double linear_tolerance[3], const std::string &operation, CasError &error)
VectorStringResult classify_rank_two_locus(int positive, int negative, double centered_constant, double zero_tolerance, const std::string &operation)
bool extract_axis_coefficients(const std::shared_ptr< SymbolicExpr > &expanded, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation, double quadratic_matrix[3][3], double linear[3], CasError &error)
VectorStringResult classify_translated_quadric(const SymmetricEigen3 &principal, int rank, const double linear[3], const std::shared_ptr< SymbolicExpr > &expanded, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
VectorStringResult classify_centered_locus(const SymmetricEigen3 &principal, int rank, double centered_constant, double zero_tolerance, const std::string &operation)
Result< double > coefficient_of_square(const std::shared_ptr< SymbolicExpr > &expanded, const std::string &variable, ComputationContext &context, const std::string &operation)
bool has_null_axis_linear_term(const SymmetricEigen3 &principal, const double linear[3], const double linear_tolerance[3])
bool extract_mixed_coefficients(const std::shared_ptr< SymbolicExpr > &expanded, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation, double quadratic_matrix[3][3], CasError &error)
Result< double > coefficient_of_linear(const std::shared_ptr< SymbolicExpr > &expanded, const std::string &variable, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
Result< CenteredQuadric > center_quadric(const SymmetricEigen3 &principal, const double linear[3], double constant, const std::string &operation)
void rotate_principal_axes(double matrix[3][3], double vectors[3][3], size_t p, size_t q)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr expand_node(const SymbolicNodePtr &node, 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
VectorStringResult classify_quadric_impl(const SurfaceSymbolic &surf, ComputationContext &context, const std::string &operation)
const std::string & variable
ComputationContext const std::string & operation
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::size_t std::size_t ComputationContext & context
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
__attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorField gradient(const std const std::vector< std::string > & vars
Result< std::string > VectorStringResult
const std::string const ExprPtr & value
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
std::shared_ptr< SymbolicExpr > F
曲面方程左端,等于零。
std::unordered_map< std::string, double > NumericBindings
std::vector< std::string > vars
坐标变量名 {x,y,z}。