LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
normalization_matrices.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5namespace {
6std::shared_ptr<const SymbolicNode> matrix_element(const MatrixNode& matrix, std::size_t index) {
7 std::shared_ptr<const SymbolicNode> value;
8 if (const auto* dense = std::get_if<MatrixNode::DenseStorage>(&matrix.storage())) {
9 if (index < dense->size()) {
10 value = (*dense)[index];
11 }
12 } else {
13 const auto& sparse = std::get<MatrixNode::SparseStorage>(matrix.storage());
14 const auto found = sparse.find(index);
15 if (found != sparse.end()) {
16 value = found->second;
17 }
18 }
19 return value ? value : detail::make_node<NumberNode>(BigInt(0));
20}
21
22bool matching_matrix_shapes(const std::vector<std::shared_ptr<const SymbolicNode>>& operands,
23 std::size_t rows, std::size_t cols) {
24 for (const auto& operand : operands) {
25 const auto matrix = std::dynamic_pointer_cast<const MatrixNode>(operand);
26 if (!matrix || matrix->rows() != rows || matrix->cols() != cols) {
27 return false;
28 }
29 }
30 return true;
31}
32}
33
35 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
36 if (operands.empty()) {
37 return false;
38 }
39 const auto first = std::dynamic_pointer_cast<const MatrixNode>(operands.front());
40 if (!first) {
41 return false;
42 }
43 const auto rows = first->rows();
44 const auto cols = first->cols();
45 if (!matching_matrix_shapes(operands, rows, cols)) {
46 return false;
47 }
49 const auto count = normalization_check_count(rewrite_budget(), rows, cols);
50 std::size_t nodes = 1;
51 elements.reserve(count);
52 for (std::size_t i = 0; i < count; ++i) {
53 std::vector<std::shared_ptr<const SymbolicNode>> terms;
54 std::size_t term_nodes = 0;
55 normalization_check_count(rewrite_budget(), operands.size(), 1, false);
56 for (const auto& operand : operands) {
57 const auto matrix = std::dynamic_pointer_cast<const MatrixNode>(operand);
58 normalization_append(rewrite_budget(), term_nodes, terms, matrix_element(*matrix, i));
59 }
61 detail::make_node<AddNode>(terms)->accept(*this);
62 normalization_append(rewrite_budget(), nodes, elements, result);
63 }
64 set_result(detail::make_node<MatrixNode>(rows, cols, elements));
65 return true;
66}
67
68std::shared_ptr<const SymbolicNode> NormalizationVisitor::matrix_product_element(
69 const MatrixNode& left, const MatrixNode& right, std::size_t row, std::size_t col) {
70 const auto* a = std::get_if<MatrixNode::DenseStorage>(&left.storage());
71 const auto* b = std::get_if<MatrixNode::DenseStorage>(&right.storage());
72 std::vector<std::shared_ptr<const SymbolicNode>> terms;
73 std::size_t nodes = 0;
75 terms.reserve(left.cols());
76 for (std::size_t k = 0; k < left.cols(); ++k) {
77 auto first = a ? (*a)[row * left.cols() + k] : matrix_element(left, row * left.cols() + k);
78 auto second = b ? (*b)[k * right.cols() + col] : matrix_element(right, k * right.cols() + col);
81 }
84 detail::make_node<AddNode>(terms)->accept(visitor);
85 return visitor.get_result();
86}
87
88std::shared_ptr<const SymbolicNode> NormalizationVisitor::fuse_matrix_product(
89 const std::shared_ptr<const SymbolicNode>& left,
90 const std::shared_ptr<const SymbolicNode>& right) {
91 const auto a = std::dynamic_pointer_cast<const MatrixNode>(left);
92 const auto b = std::dynamic_pointer_cast<const MatrixNode>(right);
93 if (!a || !b) {
94 return nullptr;
95 }
96 if (a->cols() != b->rows()) {
97 return nullptr;
98 }
100 const auto count = normalization_check_count(rewrite_budget(), a->rows(), b->cols());
101 std::size_t nodes = 1;
102 elements.reserve(count);
103 for (std::size_t row = 0; row < a->rows(); ++row) {
104 for (std::size_t col = 0; col < b->cols(); ++col) {
105 normalization_append(rewrite_budget(), nodes, elements,
106 matrix_product_element(*a, *b, row, col));
107 }
108 }
109 return detail::make_node<MatrixNode>(a->rows(), b->cols(), elements);
110}
111
112std::shared_ptr<const SymbolicNode> NormalizationVisitor::scale_matrix(
113 const MatrixNode& matrix, const std::shared_ptr<const NumberNode>& scalar) {
115 const auto count = normalization_check_count(rewrite_budget(), matrix.rows(), matrix.cols());
116 std::size_t nodes = 1;
117 elements.reserve(count);
118 for (std::size_t i = 0; i < count; ++i) {
119 auto element = matrix_element(matrix, i);
122 std::vector<std::shared_ptr<const SymbolicNode>>{scalar, element})->accept(*this);
123 normalization_append(rewrite_budget(), nodes, elements, result);
124 }
125 return detail::make_node<MatrixNode>(matrix.rows(), matrix.cols(), std::move(elements));
126}
127
128std::shared_ptr<const SymbolicNode> NormalizationVisitor::normalize_matrix_product(
129 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
130 std::vector<std::shared_ptr<const SymbolicNode>> nonscalar;
131 std::size_t nonscalar_nodes = 0;
132 auto scalar = detail::make_node<NumberNode>(BigInt(1));
133 for (const auto& operand : operands) {
134 if (const auto number = std::dynamic_pointer_cast<const NumberNode>(operand)) {
135 scalar = multiply_numbers(scalar, number);
136 } else {
137 normalization_append(rewrite_budget(), nonscalar_nodes, nonscalar, operand);
138 }
139 }
140 std::vector<std::shared_ptr<const SymbolicNode>> fused;
141 std::size_t fused_nodes = 0;
142 std::size_t last_nodes = 0;
143 if (!nonscalar.empty()) {
144 normalization_append(rewrite_budget(), fused_nodes, fused, nonscalar.front());
145 last_nodes = fused_nodes;
146 }
147 for (std::size_t i = 1; i < nonscalar.size(); ++i) {
148 if (auto product = fuse_matrix_product(fused.back(), nonscalar[i])) {
149 if (rewrite_budget()) {
150 const auto replacement_nodes = rewrite_budget()->measure(product);
151 fused_nodes = rewrite_budget()->append_size(fused_nodes - last_nodes, replacement_nodes);
152 last_nodes = replacement_nodes;
153 }
154 fused.back() = std::move(product);
155 } else {
156 const auto previous_nodes = fused_nodes;
157 normalization_append(rewrite_budget(), fused_nodes, fused, nonscalar[i]);
158 last_nodes = fused_nodes - previous_nodes;
159 }
160 }
161 if (fused.size() == 1 && !scalar->is_one()) {
162 if (const auto matrix = std::dynamic_pointer_cast<const MatrixNode>(fused.front())) {
163 return scale_matrix(*matrix, scalar);
164 }
165 }
166 if (!scalar->is_one()) {
167 if (rewrite_budget()) { (void)rewrite_budget()->append_size(fused_nodes, 1); }
168 fused.insert(fused.begin(), scalar);
169 }
171}
172}
矩阵节点,支持稠密和稀疏两种存储方式。
const std::variant< DenseStorage, SparseStorage > & storage() const noexcept
size_t cols() const noexcept
size_t rows() const noexcept
std::vector< std::shared_ptr< const SymbolicNode > > DenseStorage
稠密存储,按行优先展开。
std::shared_ptr< const SymbolicNode > scale_matrix(const MatrixNode &matrix, const std::shared_ptr< const NumberNode > &scalar)
NormalizationVisitor(detail::RewriteBudget &budget, const FactsQuery &facts, Domain domain)
void set_result(std::shared_ptr< const SymbolicNode > candidate)
std::shared_ptr< const SymbolicNode > result
bool normalize_matrix_sum(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const SymbolicNode > normalize_matrix_product(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const SymbolicNode > matrix_product_element(const MatrixNode &left, const MatrixNode &right, std::size_t row, std::size_t col)
std::shared_ptr< const SymbolicNode > fuse_matrix_product(const std::shared_ptr< const SymbolicNode > &left, const std::shared_ptr< const SymbolicNode > &right)
std::shared_ptr< const SymbolicNode > get_result() const
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
std::size_t append_size(std::size_t current, std::size_t child)
RewriteBudget * rewrite_budget() const noexcept
std::shared_ptr< const SymbolicNode > matrix_element(const MatrixNode &matrix, std::size_t index)
bool matching_matrix_shapes(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, std::size_t rows, std::size_t cols)
std::shared_ptr< const Node > make_node(Args &&... args)
const ExprPtr & element
std::size_t normalization_check_arithmetic(detail::RewriteBudget *budget, std::size_t extra_nodes, const std::shared_ptr< const Nodes > &... children)
std::size_t normalization_check_count(detail::RewriteBudget *budget, std::size_t rows, std::size_t cols=1, bool wrapped=true)
const MultiPoly & b
std::shared_ptr< const NumberNode > multiply_numbers(const std::shared_ptr< const NumberNode > &left, const std::shared_ptr< const NumberNode > &right)
两个数值节点相乘
__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
const ExprPtr & right
const std::string const ExprPtr & value
std::shared_ptr< const SymbolicNode > make_normalized_multiply_node(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, detail::RewriteBudget *budget=nullptr)
void normalization_append(detail::RewriteBudget *budget, std::size_t &nodes, std::vector< std::shared_ptr< const SymbolicNode > > &children, std::shared_ptr< const SymbolicNode > child)
符号规范化访问器接口。