LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_complex.cpp
浏览该文件的文档.
1#define _USE_MATH_DEFINES
3#include "symbolic.hpp"
6#include <cmath>
7#include <stdexcept>
8#include <variant>
9#include <type_traits>
10#include <vector>
11
12namespace LMCAS {
13
14namespace {
15
16constexpr const char* kComplexAddOperation = "complex_add";
17constexpr const char* kComplexSubOperation = "complex_sub";
18constexpr const char* kComplexMulOperation = "complex_mul";
19constexpr const char* kComplexDivOperation = "complex_div";
20constexpr const char* kComplexConjOperation = "complex_conj";
21constexpr const char* kComplexAbsOperation = "complex_abs";
22constexpr const char* kComplexArgOperation = "complex_arg";
23constexpr const char* kComplexPolarOperation = "complex_polar_form";
24constexpr const char* kComplexNthRootOperation = "solve_complex_nth_root";
25constexpr const char* kComplexQuadraticOperation = "solve_complex_quadratic";
26constexpr const char* kComplexLocusCircleOperation = "complex_locus_circle";
27constexpr const char* kComplexLocusBisectorOperation =
28 "complex_locus_perpendicular_bisector";
29
31 const char* name,
33 const std::string& operation) {
34 auto step = context.consume_steps(1, operation);
35 if (!step) return step;
36 if (!z.real || !LMCAS::detail::node(z.real)) {
38 CasErrc::InvalidArgument, std::string(name) + ".real must not be null", operation);
39 }
40 if (!z.imag || !LMCAS::detail::node(z.imag)) {
42 CasErrc::InvalidArgument, std::string(name) + ".imag must not be null", operation);
43 }
44 return Result<void>::success();
45}
46
47Result<void> validate_expr(const std::shared_ptr<SymbolicExpr>& expr,
48 const char* name,
50 const std::string& operation) {
51 auto step = context.consume_steps(1, operation);
52 if (!step) return step;
53 if (!expr || !LMCAS::detail::node(expr)) {
55 CasErrc::InvalidArgument, std::string(name) + " must not be null", operation);
56 }
57 return Result<void>::success();
58}
59
60
61template <typename T, typename F>
62Result<T> checked_construct(F&& f, const std::string& operation) {
63 try {
64 if constexpr (std::is_same_v<std::invoke_result_t<F>, Result<T>>) {
65 return f();
66 } else {
67 return Result<T>::success(f());
68 }
69 } catch (const std::bad_alloc&) {
71 "symbolic complex allocation failed", operation);
72 } catch (const std::exception& ex) {
73 return Result<T>::failure(CasErrc::InternalInvariant, ex.what(), operation);
74 }
75}
76
77} // namespace
78
81 auto va = validate_complex_symbolic(a, "a", context, kComplexAddOperation);
82 if (!va) return ComplexSymbolicResult::failure(va.error());
83 auto vb = validate_complex_symbolic(b, "b", context, kComplexAddOperation);
84 if (!vb) return ComplexSymbolicResult::failure(vb.error());
85 auto budget = context.consume_steps(4, kComplexAddOperation);
86 if (!budget) return ComplexSymbolicResult::failure(budget.error());
87 return checked_construct<ComplexSymbolic>([&]() {
88 return make_complex(SymbolicExpr::add(a.real, b.real), SymbolicExpr::add(a.imag, b.imag));
89 }, kComplexAddOperation);
90}
95
98 auto va = validate_complex_symbolic(a, "a", context, kComplexSubOperation);
99 if (!va) return ComplexSymbolicResult::failure(va.error());
100 auto vb = validate_complex_symbolic(b, "b", context, kComplexSubOperation);
101 if (!vb) return ComplexSymbolicResult::failure(vb.error());
102 auto budget = context.consume_steps(6, kComplexSubOperation);
103 if (!budget) return ComplexSymbolicResult::failure(budget.error());
104 return checked_construct<ComplexSymbolic>([&]() {
105 return make_complex(
106 SymbolicExpr::add(a.real, SymbolicExpr::multiply(SymbolicExpr::number(-1), b.real)),
107 SymbolicExpr::add(a.imag, SymbolicExpr::multiply(SymbolicExpr::number(-1), b.imag)));
108 }, kComplexSubOperation);
109}
114
117 auto va = validate_complex_symbolic(a, "a", context, kComplexMulOperation);
118 if (!va) return ComplexSymbolicResult::failure(va.error());
119 auto vb = validate_complex_symbolic(b, "b", context, kComplexMulOperation);
120 if (!vb) return ComplexSymbolicResult::failure(vb.error());
121 auto budget = context.consume_steps(10, kComplexMulOperation);
122 if (!budget) return ComplexSymbolicResult::failure(budget.error());
123 return checked_construct<ComplexSymbolic>([&]() {
124 auto real = SymbolicExpr::add(
125 SymbolicExpr::multiply(a.real, b.real),
126 SymbolicExpr::multiply(SymbolicExpr::number(-1), SymbolicExpr::multiply(a.imag, b.imag)));
127 auto imag = SymbolicExpr::add(SymbolicExpr::multiply(a.real, b.imag),
128 SymbolicExpr::multiply(a.imag, b.real));
129 return make_complex(real, imag);
130 }, kComplexMulOperation);
131}
136
139 auto va = validate_complex_symbolic(a, "a", context, kComplexDivOperation);
140 if (!va) return ComplexSymbolicResult::failure(va.error());
141 auto vb = validate_complex_symbolic(b, "b", context, kComplexDivOperation);
142 if (!vb) return ComplexSymbolicResult::failure(vb.error());
143 if (LMCAS::detail::node(b.real)->is_zero() && LMCAS::detail::node(b.imag)->is_zero()) {
145 CasErrc::DomainError, "complex division by zero", kComplexDivOperation);
146 }
147 auto budget = context.consume_steps(16, kComplexDivOperation);
148 if (!budget) return ComplexSymbolicResult::failure(budget.error());
149 return checked_construct<ComplexSymbolic>([&]() {
150 auto denom = SymbolicExpr::add(SymbolicExpr::power(b.real, SymbolicExpr::number(2)),
151 SymbolicExpr::power(b.imag, SymbolicExpr::number(2)));
152 auto real = SymbolicExpr::divide(
153 SymbolicExpr::add(SymbolicExpr::multiply(a.real, b.real), SymbolicExpr::multiply(a.imag, b.imag)),
154 denom);
155 auto imag = SymbolicExpr::divide(
156 SymbolicExpr::add(SymbolicExpr::multiply(a.imag, b.real),
157 SymbolicExpr::multiply(SymbolicExpr::number(-1),
158 SymbolicExpr::multiply(a.real, b.imag))),
159 denom);
160 return make_complex(real, imag);
161 }, kComplexDivOperation);
162}
167
169 auto vz = validate_complex_symbolic(z, "z", context, kComplexConjOperation);
170 if (!vz) return ComplexSymbolicResult::failure(vz.error());
171 auto budget = context.consume_steps(3, kComplexConjOperation);
172 if (!budget) return ComplexSymbolicResult::failure(budget.error());
173 return checked_construct<ComplexSymbolic>([&]() {
174 return make_complex(z.real, SymbolicExpr::multiply(SymbolicExpr::number(-1), z.imag));
175 }, kComplexConjOperation);
176}
181
183 auto vz = validate_complex_symbolic(z, "z", context, kComplexAbsOperation);
184 if (!vz) return ExpressionResult::failure(vz.error());
185 auto budget = context.consume_steps(8, kComplexAbsOperation);
186 if (!budget) return ExpressionResult::failure(budget.error());
187 return checked_construct<std::shared_ptr<SymbolicExpr>>([&]() {
188 return SymbolicExpr::sqrt(SymbolicExpr::add(
189 SymbolicExpr::power(z.real, SymbolicExpr::number(2)),
190 SymbolicExpr::power(z.imag, SymbolicExpr::number(2))));
191 }, kComplexAbsOperation);
192}
197
199 auto vz = validate_complex_symbolic(z, "z", context, kComplexArgOperation);
200 if (!vz) return ExpressionResult::failure(vz.error());
201 auto budget = context.consume_steps(4, kComplexArgOperation);
202 if (!budget) return ExpressionResult::failure(budget.error());
203 return checked_construct<std::shared_ptr<SymbolicExpr>>([&]() {
204 return SymbolicExpr::atan2(z.imag, z.real);
205 }, kComplexArgOperation);
206}
211
213 std::shared_ptr<SymbolicExpr> theta,
215 auto vr = validate_expr(r, "r", context, kComplexPolarOperation);
216 if (!vr) return ComplexSymbolicResult::failure(vr.error());
217 auto vt = validate_expr(theta, "theta", context, kComplexPolarOperation);
218 if (!vt) return ComplexSymbolicResult::failure(vt.error());
219 auto budget = context.consume_steps(6, kComplexPolarOperation);
220 if (!budget) return ComplexSymbolicResult::failure(budget.error());
221 return checked_construct<ComplexSymbolic>([&]() {
222 auto real = SymbolicExpr::multiply(r, SymbolicExpr::cos(theta));
223 auto imag = SymbolicExpr::multiply(r, SymbolicExpr::sin(theta));
224 return make_complex(real, imag);
225 }, kComplexPolarOperation);
226}
228 std::shared_ptr<SymbolicExpr> theta) {
230 return complex_exp_form_checked(std::move(r), std::move(theta), context);
231}
232
234 std::shared_ptr<SymbolicExpr> theta,
236 return complex_exp_form_checked(std::move(r), std::move(theta), context);
237}
239 std::shared_ptr<SymbolicExpr> theta) {
241 return complex_trig_form_checked(std::move(r), std::move(theta), context);
242}
243
244ComplexRootsResult solve_complex_nth_root_checked(std::shared_ptr<SymbolicExpr> c, int n,
246 auto vc = validate_expr(c, "c", context, kComplexNthRootOperation);
247 if (!vc) return ComplexRootsResult::failure(vc.error());
248 if (n <= 0) {
250 CasErrc::InvalidArgument, "root degree must be positive", kComplexNthRootOperation);
251 }
252 auto budget = context.consume_steps(static_cast<std::size_t>(n) * 8 + 8,
253 kComplexNthRootOperation);
254 if (!budget) return ComplexRootsResult::failure(budget.error());
255
256 const auto number = std::dynamic_pointer_cast<const NumberNode>(detail::node(c));
257 if (!number) {
260 "checked complex nth roots require a real numeric input",
261 kComplexNthRootOperation);
262 }
263
264 return checked_construct<std::vector<ComplexSymbolic>>(
265 [&]() -> ComplexRootsResult {
266 const Rational value = std::holds_alternative<BigInt>(number->value())
267 ? Rational(std::get<BigInt>(number->value()))
268 : std::get<Rational>(number->value());
269 auto radius = SymbolicExpr::power(
270 SymbolicExpr::number(value < Rational(0) ? -value : value),
271 SymbolicExpr::number(Rational(1, n)));
274 std::vector<ComplexSymbolic> roots;
275 roots.reserve(static_cast<std::size_t>(n));
276 for (int k = 0; k < n; ++k) {
277 auto angle = SymbolicExpr::multiply(
278 SymbolicExpr::number(
279 Rational(BigInt(2) * BigInt(k) +
280 BigInt(value < Rational(0) ? 1 : 0), BigInt(n))),
281 pi);
282 auto root = complex_exp_form_checked(radius, angle, context);
283 if (!root) {
284 return ComplexRootsResult::failure(root.error());
285 }
286 roots.push_back(std::move(root.value()));
287 }
288 return roots;
289 }, kComplexNthRootOperation);
290}
291ComplexRootsResult solve_complex_nth_root_checked(std::shared_ptr<SymbolicExpr> c, int n) {
293 return solve_complex_nth_root_checked(std::move(c), n, context);
294}
295
297 std::shared_ptr<SymbolicExpr> a, std::shared_ptr<SymbolicExpr> b,
298 std::shared_ptr<SymbolicExpr> c, ComputationContext& context) {
301 return checked_construct<std::vector<ComplexSymbolic>>(
302 [&]() -> ComplexRootsResult {
303 return std::vector<ComplexSymbolic>{
304 {std::move(roots.value()[0].real), std::move(roots.value()[0].imag)},
305 {std::move(roots.value()[1].real), std::move(roots.value()[1].imag)}};
306 }, kComplexQuadraticOperation);
307}
308
310 std::shared_ptr<SymbolicExpr> a, std::shared_ptr<SymbolicExpr> b,
311 std::shared_ptr<SymbolicExpr> c) {
314 std::move(a), std::move(b), std::move(c), context);
315}
316
318 const ComplexSymbolic& a, std::shared_ptr<SymbolicExpr> r,
319 const std::string& z_var, ComputationContext& context) {
320 auto va = validate_complex_symbolic(
321 a, "a", context, kComplexLocusCircleOperation);
322 if (!va) return ExpressionResult::failure(va.error());
323 auto vr = validate_expr(r, "r", context, kComplexLocusCircleOperation);
324 if (!vr) return ExpressionResult::failure(vr.error());
325 if (z_var.empty()) {
327 CasErrc::InvalidArgument, "complex variable must not be empty",
328 kComplexLocusCircleOperation);
329 }
330 return checked_construct<std::shared_ptr<SymbolicExpr>>(
331 [&]() -> ExpressionResult {
332 auto z = SymbolicExpr::variable(z_var);
333 auto difference = complex_sub_checked(
334 make_complex(z, SymbolicExpr::number(0)), a, context);
335 if (!difference) {
336 return ExpressionResult::failure(difference.error());
337 }
338 auto magnitude =
339 complex_abs_checked(difference.value(), context);
340 if (!magnitude) {
341 return ExpressionResult::failure(magnitude.error());
342 }
343 return SymbolicExpr::eq(magnitude.value(), r);
344 }, kComplexLocusCircleOperation);
345}
346
348 const ComplexSymbolic& a, std::shared_ptr<SymbolicExpr> r,
349 const std::string& z_var) {
351 return complex_locus_circle_checked(a, std::move(r), z_var, context);
352}
353
355 const ComplexSymbolic& a, const ComplexSymbolic& b,
356 const std::string& z_var, ComputationContext& context) {
357 auto va = validate_complex_symbolic(
358 a, "a", context, kComplexLocusBisectorOperation);
359 if (!va) return ExpressionResult::failure(va.error());
360 auto vb = validate_complex_symbolic(
361 b, "b", context, kComplexLocusBisectorOperation);
362 if (!vb) return ExpressionResult::failure(vb.error());
363 if (z_var.empty()) {
365 CasErrc::InvalidArgument, "complex variable must not be empty",
366 kComplexLocusBisectorOperation);
367 }
368 return checked_construct<std::shared_ptr<SymbolicExpr>>(
369 [&]() -> ExpressionResult {
370 auto z = SymbolicExpr::variable(z_var);
371 auto z_as_complex =
372 make_complex(z, SymbolicExpr::number(0));
373 auto from_a = complex_sub_checked(z_as_complex, a, context);
374 if (!from_a) return ExpressionResult::failure(from_a.error());
375 auto from_b = complex_sub_checked(z_as_complex, b, context);
376 if (!from_b) return ExpressionResult::failure(from_b.error());
377 auto distance_a =
378 complex_abs_checked(from_a.value(), context);
379 if (!distance_a) {
380 return ExpressionResult::failure(distance_a.error());
381 }
382 auto distance_b =
383 complex_abs_checked(from_b.value(), context);
384 if (!distance_b) {
385 return ExpressionResult::failure(distance_b.error());
386 }
387 return SymbolicExpr::eq(distance_a.value(), distance_b.value());
388 }, kComplexLocusBisectorOperation);
389}
390
398
399}
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
virtual bool is_zero() const
Result< void > validate_complex_symbolic(const ComplexSymbolic &z, const char *name, ComputationContext &context, const std::string &operation)
Result< void > validate_expr(const std::shared_ptr< SymbolicExpr > &expr, const char *name, ComputationContext &context, const std::string &operation)
Result< T > checked_construct(F &&f, const std::string &operation)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< CartesianQuadraticRoots > real_quadratic_roots_checked(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, ComputationContext &context)
std::shared_ptr< const Node > make_node(Args &&... args)
ComplexSymbolicResult complex_div_checked(const ComplexSymbolic &a, const ComplexSymbolic &b, ComputationContext &context)
ExpressionResult complex_abs_checked(const ComplexSymbolic &z, ComputationContext &context)
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ComplexRootsResult solve_complex_quadratic_checked(std::shared_ptr< SymbolicExpr > a, std::shared_ptr< SymbolicExpr > b, std::shared_ptr< SymbolicExpr > c, ComputationContext &context)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
ExpressionResult complex_locus_perpendicular_bisector_checked(const ComplexSymbolic &a, const ComplexSymbolic &b, const std::string &z_var, ComputationContext &context)
const VectorField const VectorField & c
ComplexSymbolicResult complex_sub_checked(const ComplexSymbolic &a, const ComplexSymbolic &b, ComputationContext &context)
ComplexSymbolic make_complex(std::shared_ptr< SymbolicExpr > real, std::shared_ptr< SymbolicExpr > imag)
构造符号复数
const MultiPoly & b
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
ComplexRootsResult solve_complex_nth_root_checked(std::shared_ptr< SymbolicExpr > c, int n, ComputationContext &context)
ComplexSymbolicResult complex_conj_checked(const ComplexSymbolic &z, ComputationContext &context)
__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
ExpressionResult complex_locus_circle_checked(const ComplexSymbolic &a, std::shared_ptr< SymbolicExpr > r, const std::string &z_var, ComputationContext &context)
ComplexSymbolicResult complex_add_checked(const ComplexSymbolic &a, const ComplexSymbolic &b, ComputationContext &context)
Result< ComplexSymbolic > ComplexSymbolicResult
ExprPtr imag
std::shared_ptr< SymbolicExpr > real
实部
ComplexSymbolicResult complex_trig_form_checked(std::shared_ptr< SymbolicExpr > r, std::shared_ptr< SymbolicExpr > theta, ComputationContext &context)
ComplexSymbolicResult complex_exp_form_checked(std::shared_ptr< SymbolicExpr > r, std::shared_ptr< SymbolicExpr > theta, ComputationContext &context)
ExprResult pi()
std::shared_ptr< SymbolicExpr > imag
虚部
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
ComplexSymbolicResult complex_mul_checked(const ComplexSymbolic &a, const ComplexSymbolic &b, ComputationContext &context)
const std::string const ExprPtr & value
ExpressionResult complex_arg_checked(const ComplexSymbolic &z, ComputationContext &context)
Result< std::vector< ComplexSymbolic > > ComplexRootsResult
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > const std::string & z_var
符号复数,由实部和虚部组成
符号规范化访问器接口。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
符号复数运算:加减乘除、共轭、模、辐角、极坐标形式。