OASIS
Open Algebra Software
Loading...
Searching...
No Matches
BoundedBinaryExpression.hpp
Go to the documentation of this file.
1//
2// Created by Matthew McCall on 5/2/24.
3//
4
5#ifndef OASIS_BOUNDEDBINARYEXPRESSION_HPP
6#define OASIS_BOUNDEDBINARYEXPRESSION_HPP
7
9#include "Expression.hpp"
10#include "RecursiveCast.hpp"
11#include "Visit.hpp"
12
13namespace Oasis {
24template <template <IExpression, IExpression, IExpression, IExpression> class DerivedT, IExpression MostSigOpT = Expression, IExpression LeastSigOpT = MostSigOpT, IExpression LowerBoundT = Expression, IExpression UpperBoundT = LowerBoundT>
25class BoundedBinaryExpression : public BoundedExpression<LowerBoundT, UpperBoundT> {
26
27 using DerivedSpecialized = DerivedT<MostSigOpT, LeastSigOpT, LowerBoundT, UpperBoundT>;
28 using DerivedGeneralized = DerivedT<Expression, Expression, Expression, Expression>;
29
30public:
33 {
34 if (other.HasMostSigOp()) {
36 }
37
38 if (other.HasLeastSigOp()) {
40 }
41 }
42
43 BoundedBinaryExpression(const MostSigOpT& mostSigOp, const LeastSigOpT& leastSigOp)
44 {
45 SetMostSigOp(mostSigOp);
46 SetLeastSigOp(leastSigOp);
47 }
48
49 [[nodiscard]] auto Copy() const -> std::unique_ptr<Expression> final
50 {
51 return std::make_unique<DerivedSpecialized>(*static_cast<const DerivedSpecialized*>(this));
52 }
53
54 auto Copy(tf::Subflow& subflow) const -> std::unique_ptr<Expression> final
55 {
56 DerivedSpecialized copy;
57
58 if (this->mostSigOp) {
59 subflow.emplace([this, &copy](tf::Subflow& sbf) {
60 copy.SetMostSigOp(mostSigOp->Copy(sbf), sbf);
61 });
62 }
63
64 if (this->leastSigOp) {
65 subflow.emplace([this, &copy](tf::Subflow& sbf) {
66 copy.SetLeastSigOp(leastSigOp->Copy(sbf), sbf);
67 });
68 }
69
70 subflow.join();
71
73 }
74
75 [[nodiscard]] auto Equals(const Expression& other) const -> bool final
76 {
77 if (this->GetType() != other.GetType()) {
78 return false;
79 }
80
81 const auto otherGeneralized = other.Generalize();
82 const auto& otherBinaryGeneralized = static_cast<const DerivedGeneralized&>(*otherGeneralized);
83
84 bool mostSigOpMismatch = false, leastSigOpMismatch = false;
85
86 if (this->HasMostSigOp() == otherBinaryGeneralized.HasMostSigOp()) {
87 if (mostSigOp && otherBinaryGeneralized.HasMostSigOp()) {
88 mostSigOpMismatch = !mostSigOp->Equals(otherBinaryGeneralized.GetMostSigOp());
89 }
90 } else {
91 mostSigOpMismatch = true;
92 }
93
94 if (this->HasLeastSigOp() == otherBinaryGeneralized.HasLeastSigOp()) {
95 if (this->HasLeastSigOp() && otherBinaryGeneralized.HasLeastSigOp()) {
96 leastSigOpMismatch = !leastSigOp->Equals(otherBinaryGeneralized.GetLeastSigOp());
97 }
98 } else {
99 mostSigOpMismatch = true;
100 }
101
102 if (!mostSigOpMismatch && !leastSigOpMismatch) {
103 return true;
104 }
105
106 if (!(this->GetCategory() & Associative)) {
107 return false;
108 }
109
110 auto thisFlattened = std::vector<std::unique_ptr<Expression>> {};
111 auto otherFlattened = std::vector<std::unique_ptr<Expression>> {};
112
113 this->Flatten(thisFlattened);
114 otherBinaryGeneralized.Flatten(otherFlattened);
115
116 for (const auto& thisOperand : thisFlattened) {
117 if (std::find_if(otherFlattened.begin(), otherFlattened.end(), [&thisOperand](const auto& otherOperand) {
118 return thisOperand->Equals(*otherOperand);
119 })
120 == otherFlattened.end()) {
121 return false;
122 }
123 }
124
125 return true;
126 }
127
128 [[nodiscard]] auto Generalize() const -> std::unique_ptr<Expression> final
129 {
130 DerivedGeneralized generalized;
131
132 if (this->mostSigOp) {
133 generalized.SetMostSigOp(*this->mostSigOp->Copy());
134 }
135
136 if (this->leastSigOp) {
137 generalized.SetLeastSigOp(*this->leastSigOp->Copy());
138 }
139
140 return std::make_unique<DerivedGeneralized>(generalized);
141 }
142
143 auto Generalize(tf::Subflow& subflow) const -> std::unique_ptr<Expression> final
144 {
145 DerivedGeneralized generalized;
146
147 if (this->mostSigOp) {
148 subflow.emplace([this, &generalized](tf::Subflow& sbf) {
149 generalized.SetMostSigOp(*this->mostSigOp->Copy(sbf));
150 });
151 }
152
153 if (this->leastSigOp) {
154 subflow.emplace([this, &generalized](tf::Subflow& sbf) {
155 generalized.SetLeastSigOp(*this->leastSigOp->Copy(sbf));
156 });
157 }
158
159 subflow.join();
160
161 return std::make_unique<DerivedGeneralized>(generalized);
162 }
163
164 auto Simplify(tf::Subflow& subflow) const -> std::unique_ptr<Expression> override
165 {
166 std::unique_ptr<Expression> generalized, simplified;
167
168 tf::Task generalizeTask = subflow.emplace([this, &generalized](tf::Subflow& sbf) {
169 generalized = Generalize(sbf);
170 });
171
172 tf::Task simplifyTask = subflow.emplace([&generalized, &simplified](tf::Subflow& sbf) {
173 simplified = generalized->Simplify(sbf);
174 });
175
176 simplifyTask.succeed(generalizeTask);
177 subflow.join();
178
179 return simplified;
180 }
181
182 [[nodiscard]] auto StructurallyEquivalent(const Expression& other) const -> bool final
183 {
184 if (this->GetType() != other.GetType()) {
185 return false;
186 }
187
188 const std::unique_ptr<Expression> otherGeneralized = other.Generalize();
189 const auto& otherBinaryGeneralized = static_cast<const DerivedGeneralized&>(*otherGeneralized);
190
191 if (this->HasMostSigOp() == otherBinaryGeneralized.HasMostSigOp()) {
192 if (this->HasMostSigOp() && otherBinaryGeneralized.HasMostSigOp()) {
193 if (!mostSigOp->StructurallyEquivalent(otherBinaryGeneralized.GetMostSigOp())) {
194 return false;
195 }
196 }
197 }
198
199 if (this->HasLeastSigOp() == otherBinaryGeneralized.HasLeastSigOp()) {
200 if (this->HasLeastSigOp() && otherBinaryGeneralized.HasLeastSigOp()) {
201 if (!leastSigOp->StructurallyEquivalent(otherBinaryGeneralized.GetLeastSigOp())) {
202 return false;
203 }
204 }
205 }
206
207 return true;
208 }
209
210 auto StructurallyEquivalent(const Expression& other, tf::Subflow& subflow) const -> bool final
211 {
212 if (this->GetType() != other.GetType()) {
213 return false;
214 }
215
216 std::unique_ptr<Expression> otherGeneralized;
217
218 tf::Task generalizeTask = subflow.emplace([&](tf::Subflow& sbf) {
219 otherGeneralized = other.Generalize(sbf);
220 });
221
222 bool mostSigOpEquivalent = false, leastSigOpEquivalent = false;
223
224 if (this->mostSigOp) {
225 tf::Task compMostSigOp = subflow.emplace([this, &otherGeneralized, &mostSigOpEquivalent](tf::Subflow& sbf) {
226 if (const auto& otherBinary = static_cast<const DerivedGeneralized&>(*otherGeneralized); otherBinary.HasMostSigOp()) {
227 mostSigOpEquivalent = mostSigOp->StructurallyEquivalent(otherBinary.GetMostSigOp(), sbf);
228 }
229 });
230
231 compMostSigOp.succeed(generalizeTask);
232 }
233
234 if (this->leastSigOp) {
235 tf::Task compLeastSigOp = subflow.emplace([this, &otherGeneralized, &leastSigOpEquivalent](tf::Subflow& sbf) {
236 if (const auto& otherBinary = static_cast<const DerivedGeneralized&>(*otherGeneralized); otherBinary.HasLeastSigOp()) {
237 leastSigOpEquivalent = leastSigOp->StructurallyEquivalent(otherBinary.GetLeastSigOp(), sbf);
238 }
239 });
240
241 compLeastSigOp.succeed(generalizeTask);
242 }
243
244 subflow.join();
245
246 return mostSigOpEquivalent && leastSigOpEquivalent;
247 }
248
261 {
262 if (this->mostSigOp->template Is<DerivedT>()) {
263 auto generalizedMostSigOp = this->mostSigOp->Generalize();
264 const auto& mostSigOp = static_cast<const DerivedGeneralized&>(*generalizedMostSigOp);
265 mostSigOp.Flatten(out);
266 } else {
267 out.push_back(this->mostSigOp->Copy());
268 }
269
270 if (this->leastSigOp->template Is<DerivedT>()) {
271 auto generalizedLeastSigOp = this->leastSigOp->Generalize();
272 const auto& leastSigOp = static_cast<const DerivedGeneralized&>(*generalizedLeastSigOp);
273 leastSigOp.Flatten(out);
274 } else {
275 out.push_back(this->leastSigOp->Copy());
276 }
277 }
278
283 auto GetMostSigOp() const -> const MostSigOpT&
284 {
285 assert(mostSigOp != nullptr);
286 return *mostSigOp;
287 }
288
293 auto GetLeastSigOp() const -> const LeastSigOpT&
294 {
295 assert(leastSigOp != nullptr);
296 return *leastSigOp;
297 }
298
303 [[nodiscard]] auto HasMostSigOp() const -> bool
304 {
305 return mostSigOp != nullptr;
306 }
307
312 [[nodiscard]] auto HasLeastSigOp() const -> bool
313 {
314 return leastSigOp != nullptr;
315 }
316
321 template <typename T>
323 auto SetMostSigOp(const T& op) -> bool
324 {
326 this->mostSigOp = op.Copy();
327 return true;
328 }
329
331 this->mostSigOp = std::make_unique<MostSigOpT>(op);
332 return true;
333 }
334
335 if (auto castedOp = Oasis::RecursiveCast<MostSigOpT>(op); castedOp) {
336 mostSigOp = std::move(castedOp);
337 return true;
338 }
339
340 return false;
341 }
342
347 template <typename T>
349 auto SetLeastSigOp(const T& op) -> bool
350 {
352 this->leastSigOp = op.Copy();
353 return true;
354 }
355
357 this->leastSigOp = std::make_unique<LeastSigOpT>(op);
358 return true;
359 }
360
361 if (auto castedOp = Oasis::RecursiveCast<LeastSigOpT>(op); castedOp) {
362 leastSigOp = std::move(castedOp);
363 return true;
364 }
365
366 return false;
367 }
368
369 auto Substitute(const Expression& var, const Expression& val) -> std::unique_ptr<Expression> override
370 {
371 const std::unique_ptr<Expression> left = GetMostSigOp().Substitute(var, val);
372 const std::unique_ptr<Expression> right = GetLeastSigOp().Substitute(var, val);
373 DerivedGeneralized comb { *left, *right };
374 // auto ret = comb.Simplify();
375 // return ret;
376 return comb;
377 }
382 auto SwapOperands() const -> DerivedSpecialized
383 {
384 return DerivedT { *this->leastSigOp, *this->mostSigOp };
385 }
386
388
389 void Serialize(SerializationVisitor& visitor) const override
390 {
391 const auto generalized = Generalize();
392 const auto& derivedGeneralized = dynamic_cast<const DerivedGeneralized&>(*generalized);
393 visitor.Serialize(derivedGeneralized);
394 }
395
396private:
399};
400
401}
402
403#endif // OASIS_BOUNDEDBINARYEXPRESSION_HPP
A concept for an operand of a binary expression with bounds.
Definition BoundedBinaryExpression.hpp:25
auto SwapOperands() const -> DerivedSpecialized
Swaps the operands of this expression.
Definition BoundedBinaryExpression.hpp:382
auto GetMostSigOp() const -> const MostSigOpT &
Gets the most significant operand of this expression.
Definition BoundedBinaryExpression.hpp:283
auto Flatten(std::vector< std::unique_ptr< Expression > > &out) const -> void
Flattens this expression.
Definition BoundedBinaryExpression.hpp:260
auto Simplify(tf::Subflow &subflow) const -> std::unique_ptr< Expression > override
Definition BoundedBinaryExpression.hpp:164
BoundedBinaryExpression(const MostSigOpT &mostSigOp, const LeastSigOpT &leastSigOp)
Definition BoundedBinaryExpression.hpp:43
auto Substitute(const Expression &var, const Expression &val) -> std::unique_ptr< Expression > override
Definition BoundedBinaryExpression.hpp:369
auto Equals(const Expression &other) const -> bool final
Compares this expression to another expression for equality.
Definition BoundedBinaryExpression.hpp:75
auto SetMostSigOp(const T &op) -> bool
Sets the most significant operand of this expression.
Definition BoundedBinaryExpression.hpp:323
auto Generalize() const -> std::unique_ptr< Expression > final
Converts this expression to a more general expression.
Definition BoundedBinaryExpression.hpp:128
auto HasMostSigOp() const -> bool
Gets whether this expression has a most significant operand.
Definition BoundedBinaryExpression.hpp:303
void Serialize(SerializationVisitor &visitor) const override
Definition BoundedBinaryExpression.hpp:389
auto GetLeastSigOp() const -> const LeastSigOpT &
Gets the least significant operand of this expression.
Definition BoundedBinaryExpression.hpp:293
auto HasLeastSigOp() const -> bool
Gets whether this expression has a least significant operand.
Definition BoundedBinaryExpression.hpp:312
auto SetLeastSigOp(const T &op) -> bool
Sets the least significant operand of this expression.
Definition BoundedBinaryExpression.hpp:349
auto Generalize(tf::Subflow &subflow) const -> std::unique_ptr< Expression > final
Definition BoundedBinaryExpression.hpp:143
auto Copy(tf::Subflow &subflow) const -> std::unique_ptr< Expression > final
Definition BoundedBinaryExpression.hpp:54
auto Copy() const -> std::unique_ptr< Expression > final
Copies this expression.
Definition BoundedBinaryExpression.hpp:49
auto StructurallyEquivalent(const Expression &other) const -> bool final
Checks whether this expression is structurally equivalent to another expression.
Definition BoundedBinaryExpression.hpp:182
auto operator=(const BoundedBinaryExpression &other) -> BoundedBinaryExpression &=default
auto StructurallyEquivalent(const Expression &other, tf::Subflow &subflow) const -> bool final
Definition BoundedBinaryExpression.hpp:210
BoundedBinaryExpression(const BoundedBinaryExpression &other)
Definition BoundedBinaryExpression.hpp:32
A concept base class for both Unary and BoundedBinary expressions.
Definition BoundedExpression.hpp:23
An expression.
Definition Expression.hpp:63
virtual auto GetCategory() const -> uint32_t
Gets the category of this expression.
Definition Expression.cpp:221
virtual auto GetType() const -> ExpressionType
Gets the type of this expression.
Definition Expression.cpp:236
Checks if type T is same as any of the provided types in U.
Definition Concepts.hpp:53
T find_if(T... args)
T is_same_v
Definition Add.hpp:11
@ Associative
Definition Expression.hpp:50