LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_construction.cpp
浏览该文件的文档.
1#include "symbolic.hpp"
5#include <charconv>
6#include <cmath>
7#include <exception>
8#include <new>
9#include <utility>
10
11namespace LMCAS {
12
13namespace {
14Rational decimal_rational(lmmc_real_t value) {
15 if (!std::isfinite(value)) {
16 throw std::invalid_argument("approximate number must be finite");
17 }
18 char token[64];
19 const auto formatted = std::to_chars(
20 token, token + sizeof(token), value, std::chars_format::general);
21 if (formatted.ec != std::errc{}) {
22 throw std::logic_error("finite double formatting failed");
23 }
24 return Rational(std::string(token, formatted.ptr));
25}
26}
27
28NumberNode::NumberNode(lmmc_real_t value) : value_(decimal_rational(value)) {}
29
31 constexpr const char* operation = "LMCAS.constant";
32 try {
33 auto expression = LMCAS::detail::make_expression_ptr(
35 if (!expression || !LMCAS::detail::node(expression)) {
37 "constant factory returned null",
38 operation);
39 }
40 return ExpressionResult::success(std::move(expression));
41 } catch (const std::bad_alloc&) {
43 "constant allocation failed",
44 operation);
45 } catch (const std::exception& error) {
47 operation);
48 }
49}
50
51std::shared_ptr<SymbolicExpr> SymbolicExpr::number(int n) {
54}
55
56
57std::shared_ptr<SymbolicExpr> SymbolicExpr::number(double n) {
59 LMCAS::detail::make_node<NumberNode>(static_cast<lmmc_real_t>(n)));
60}
61
62std::shared_ptr<SymbolicExpr> SymbolicExpr::number(const BigInt& value) {
65}
66
67std::shared_ptr<SymbolicExpr> SymbolicExpr::number(const Rational& value) {
70}
71
72std::shared_ptr<SymbolicExpr> SymbolicExpr::infinity(int sign) {
75 std::vector<std::shared_ptr<const SymbolicNode>>{});
76 auto expression = LMCAS::detail::make_expression_ptr(node);
77 return sign < 0 ? multiply(number(-1), expression) : expression;
78}
79
80std::shared_ptr<SymbolicExpr> SymbolicExpr::sqrt(
81 std::shared_ptr<SymbolicExpr> operand) {
82 if (!operand || !operand->impl_->root) {
83 throw std::invalid_argument("sqrt operand cannot be null");
84 }
87 LMCAS::detail::make_node<PowerNode>(operand->impl_->root, half));
88}
89
90std::shared_ptr<SymbolicExpr> SymbolicExpr::multiply(
91 std::shared_ptr<SymbolicExpr> left,
92 std::shared_ptr<SymbolicExpr> right) {
93 if (!left || !left->impl_->root || !right || !right->impl_->root) {
94 throw std::invalid_argument("multiply operands cannot be null");
95 }
96 std::vector<std::shared_ptr<const SymbolicNode>> operands{
97 left->impl_->root, right->impl_->root};
99 LMCAS::detail::make_node<MultiplyNode>(std::move(operands)));
100}
101
102std::shared_ptr<SymbolicExpr> SymbolicExpr::add(
103 std::shared_ptr<SymbolicExpr> left,
104 std::shared_ptr<SymbolicExpr> right) {
105 if (!left || !left->impl_->root || !right || !right->impl_->root) {
106 throw std::invalid_argument("add operands cannot be null");
107 }
108 std::vector<std::shared_ptr<const SymbolicNode>> operands{
109 left->impl_->root, right->impl_->root};
111 LMCAS::detail::make_node<AddNode>(std::move(operands)));
112}
113
114std::shared_ptr<SymbolicExpr> SymbolicExpr::power(
115 std::shared_ptr<SymbolicExpr> base,
116 std::shared_ptr<SymbolicExpr> exponent) {
117 if (!base || !base->impl_->root || !exponent || !exponent->impl_->root) {
118 throw std::invalid_argument("power operands cannot be null");
119 }
121 LMCAS::detail::make_node<PowerNode>(base->impl_->root, exponent->impl_->root));
122}
123
124std::shared_ptr<SymbolicExpr> SymbolicExpr::sin(
125 std::shared_ptr<SymbolicExpr> operand) {
126 if (!operand || !operand->impl_->root) {
127 throw std::invalid_argument("sin operand cannot be null");
128 }
132 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
133}
134
135std::shared_ptr<SymbolicExpr> SymbolicExpr::cos(
136 std::shared_ptr<SymbolicExpr> operand) {
137 if (!operand || !operand->impl_->root) {
138 throw std::invalid_argument("cos operand cannot be null");
139 }
143 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
144}
145
146std::shared_ptr<SymbolicExpr> SymbolicExpr::tan(
147 std::shared_ptr<SymbolicExpr> operand) {
148 if (!operand || !operand->impl_->root) {
149 throw std::invalid_argument("tan operand cannot be null");
150 }
154 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
155}
156
157std::shared_ptr<SymbolicExpr> SymbolicExpr::ln(
158 std::shared_ptr<SymbolicExpr> operand) {
159 if (!operand || !operand->impl_->root) {
160 throw std::invalid_argument("ln operand cannot be null");
161 }
165 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
166}
167
168std::shared_ptr<SymbolicExpr> SymbolicExpr::exp(
169 std::shared_ptr<SymbolicExpr> operand) {
170 if (!operand || !operand->impl_->root) {
171 throw std::invalid_argument("exp operand cannot be null");
172 }
176 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
177}
178
179std::shared_ptr<SymbolicExpr> SymbolicExpr::lambertw(
180 std::shared_ptr<SymbolicExpr> operand) {
181 if (!operand || !operand->impl_->root) {
182 throw std::invalid_argument("lambertw operand cannot be null");
183 }
187 std::vector<std::shared_ptr<const SymbolicNode>>{operand->impl_->root}));
188}
189
190std::shared_ptr<SymbolicExpr> SymbolicExpr::log(
191 std::shared_ptr<SymbolicExpr> value,
192 std::shared_ptr<SymbolicExpr> base) {
193 if (!value || !value->impl_->root || !base || !base->impl_->root) {
194 throw std::invalid_argument("log operands cannot be null");
195 }
199 std::vector<std::shared_ptr<const SymbolicNode>>{
200 value->impl_->root, base->impl_->root}));
201}
202
203std::shared_ptr<SymbolicExpr> SymbolicExpr::atan2(
204 std::shared_ptr<SymbolicExpr> y,
205 std::shared_ptr<SymbolicExpr> x) {
206 if (!y || !y->impl_->root || !x || !x->impl_->root) {
207 throw std::invalid_argument("atan2 operands cannot be null");
208 }
212 std::vector<std::shared_ptr<const SymbolicNode>>{y->impl_->root, x->impl_->root}));
213}
214
215std::shared_ptr<SymbolicExpr> SymbolicExpr::root_of(
216 std::shared_ptr<SymbolicExpr> polynomial,
217 const std::string& variable_name,
218 int index) {
219 if (!polynomial || !polynomial->impl_->root) {
220 throw std::invalid_argument("root_of polynomial cannot be null");
221 }
222 if (index < 0) throw std::invalid_argument("root_of index cannot be negative");
223 auto result = LMCAS::make_rootof_checked(
224 polynomial, variable_name, static_cast<std::size_t>(index));
225 if (!result) throw std::invalid_argument(result.error().message);
226 return std::move(result.value());
227}
228
229std::shared_ptr<SymbolicExpr> SymbolicExpr::eq(
230 std::shared_ptr<SymbolicExpr> left,
231 std::shared_ptr<SymbolicExpr> right) {
232 if (!left || !left->impl_->root || !right || !right->impl_->root) {
233 throw std::invalid_argument("eq operands cannot be null");
234 }
237 left->impl_->root, right->impl_->root, RelationalNode::Op::EQ));
238}
239
240std::shared_ptr<SymbolicExpr> SymbolicExpr::matrix(
241 const std::vector<std::vector<std::shared_ptr<SymbolicExpr>>>& elements) {
242 if (elements.empty()) {
243 throw std::invalid_argument("matrix requires at least one row");
244 }
245 const std::size_t column_count = elements.front().size();
246 if (column_count == 0) {
247 throw std::invalid_argument("matrix requires at least one column");
248 }
249
250 std::vector<std::vector<std::shared_ptr<const SymbolicNode>>> node_elements;
251 node_elements.reserve(elements.size());
252 for (const auto& row : elements) {
253 if (row.size() != column_count) {
254 throw std::invalid_argument(
255 "matrix rows must have the same number of columns");
256 }
257 std::vector<std::shared_ptr<const SymbolicNode>> node_row;
258 node_row.reserve(row.size());
259 for (const auto& element : row) {
260 if (!element || !element->impl_->root) {
261 throw std::invalid_argument("matrix elements cannot be null");
262 }
263 node_row.push_back(element->impl_->root);
264 }
265 node_elements.push_back(std::move(node_row));
266 }
268 LMCAS::detail::make_node<MatrixNode>(std::move(node_elements)));
269}
270
271std::shared_ptr<SymbolicExpr> SymbolicExpr::variable(
272 const std::string& name) {
275}
276
277std::shared_ptr<SymbolicExpr> SymbolicExpr::divide(const std::shared_ptr<SymbolicExpr>& num, const std::shared_ptr<SymbolicExpr>& den) {
278 return SymbolicExpr::multiply(num, SymbolicExpr::power(den, SymbolicExpr::number(-1)));
279}
280
281std::shared_ptr<SymbolicExpr> SymbolicExpr::make_integral(
282 const std::shared_ptr<SymbolicExpr>& expression,
283 const std::string& variable) {
284 if (!expression) return nullptr;
287 LMCAS::detail::node(expression), variable));
288}
289
290}
@ Atan2
双参数反正切。
const std::variant< BigInt, Rational > & value() const noexcept
NumberNode(const BigInt &v)
const std::variant< BigInt, Rational > value_
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::shared_ptr< SymbolicExpr > value)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ExpressionResult constant_expression(const char *name)
std::shared_ptr< const Node > make_node(Args &&... args)
ComputationContext const std::string & operation
std::shared_ptr< SymbolicExpr > num(int value)
const std::string & variable
const ExprPtr & element
@ Rational
Rational numbers
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
RootOfConstructionResult make_rootof_checked(const std::shared_ptr< SymbolicExpr > &polynomial, const std::string &variable, std::size_t index, ComputationContext &context)
const ExprPtr & exponent
const ExprPtr & right
const std::string const ExprPtr & value
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
精确 RootOf 标识构造及受检数值求值。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
内部 AST 定义。