Skip to content

Commit d28f4ba

Browse files
taminobburgholzer
andauthored
♻️ Refactor getStaticParameter to valueToDouble (#1443)
## Description This PR reduces the current code duplication of `getStaticParameter` which is used in both `QC` and `QCO`. It additionally adds the conversion to a standard C++ double type since there is no other use of the function in the code base so far. An alternative to the currently returned `std::optional` would be a `llvm::FailureOr<double>` which is simply a subclass of `std::optional`. However, it is in my opinion slightly more annoying to use since it requires `llvm::succeeded` and `llvm::failed` to check the result instead of the implicit conversion to bool available in `std::optional`. This is meant to make it slightly safer to use, but makes the code also more verbose and less convenient which is why I decided against using it. `std::optional` is an established standard C++ tool and people usually know how to handle it correctly which cannot be said for `llvm::FailureOr<double>`. Required for #1426 ## Checklist: <!--- This checklist serves as a reminder of a couple of things that ensure your pull request will be merged swiftly. --> - [ ] The pull request only contains commits that are focused and relevant to this change. - [ ] I have added appropriate tests that cover the new/changed functionality. - [ ] I have updated the documentation to reflect these changes. - [ ] I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals. - [ ] I have added migration instructions to the upgrade guide (if needed). - [ ] The changes follow the project's style guidelines and introduce no new warnings. - [ ] The changes are fully tested and pass the CI checks. - [ ] I have reviewed my own code changes. --------- Signed-off-by: Tamino Bauknecht <28907748+taminob@users.noreply.github.com> Co-authored-by: Lukas Burgholzer <burgholzer@me.com>
1 parent a26be01 commit d28f4ba

15 files changed

Lines changed: 223 additions & 124 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
1111

1212
### Added
1313

14-
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**])
14+
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436], [#1443]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**])
1515

1616
### Changed
1717

@@ -307,6 +307,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
307307

308308
<!-- PR links -->
309309

310+
[#1443]: https://github.com/munich-quantum-toolkit/core/pull/1443
310311
[#1437]: https://github.com/munich-quantum-toolkit/core/pull/1437
311312
[#1436]: https://github.com/munich-quantum-toolkit/core/pull/1436
312313
[#1430]: https://github.com/munich-quantum-toolkit/core/pull/1430

mlir/include/mlir/Dialect/QC/IR/QCDialect.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,6 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
101101
}
102102
return this->getOperation()->getOperand(T + i);
103103
}
104-
105-
[[nodiscard]] static FloatAttr getStaticParameter(Value param) {
106-
auto constantOp = param.getDefiningOp<arith::ConstantOp>();
107-
if (!constantOp) {
108-
return nullptr;
109-
}
110-
return dyn_cast<FloatAttr>(constantOp.getValue());
111-
}
112104
};
113105
};
114106

mlir/include/mlir/Dialect/QCO/IR/QCODialect.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
108108
return this->getOperation()->getOperand(T + i);
109109
}
110110

111-
[[nodiscard]] static FloatAttr getStaticParameter(Value param) {
112-
auto constantOp = param.getDefiningOp<arith::ConstantOp>();
113-
if (!constantOp) {
114-
return nullptr;
115-
}
116-
return dyn_cast<FloatAttr>(constantOp.getValue());
117-
}
118-
119111
Value getInputForOutput(Value output) {
120112
const auto& op = this->getOperation();
121113
for (size_t i = 0; i < T; ++i) {

mlir/include/mlir/Dialect/QCO/QCOUtils.h

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
#pragma once
1212

13+
#include "mlir/Dialect/Utils/Utils.h"
14+
1315
#include <mlir/Dialect/Arith/IR/Arith.h>
14-
#include <mlir/Dialect/Utils/Utils.h>
1516
#include <mlir/IR/PatternMatch.h>
1617

1718
namespace mlir::qco {
@@ -188,13 +189,8 @@ mergeTwoTargetOneParameter(OpType op, mlir::PatternRewriter& rewriter) {
188189
template <typename OpType>
189190
inline mlir::LogicalResult
190191
removeTrivialOneTargetOneParameter(OpType op, mlir::PatternRewriter& rewriter) {
191-
const auto paramAttr = OpType::getStaticParameter(op.getOperand(1));
192-
if (!paramAttr) {
193-
return failure();
194-
}
195-
196-
const auto paramValue = paramAttr.getValueAsDouble();
197-
if (std::abs(paramValue) > utils::TOLERANCE) {
192+
const auto param = utils::valueToDouble(op.getOperand(1));
193+
if (!param || std::abs(*param) > utils::TOLERANCE) {
198194
return failure();
199195
}
200196

@@ -215,13 +211,8 @@ removeTrivialOneTargetOneParameter(OpType op, mlir::PatternRewriter& rewriter) {
215211
template <typename OpType>
216212
inline mlir::LogicalResult
217213
removeTrivialTwoTargetOneParameter(OpType op, mlir::PatternRewriter& rewriter) {
218-
const auto paramAttr = OpType::getStaticParameter(op.getOperand(2));
219-
if (!paramAttr) {
220-
return failure();
221-
}
222-
223-
const auto paramValue = paramAttr.getValueAsDouble();
224-
if (std::abs(paramValue) > utils::TOLERANCE) {
214+
const auto param = utils::valueToDouble(op.getOperand(2));
215+
if (!param || std::abs(*param) > utils::TOLERANCE) {
225216
return failure();
226217
}
227218

mlir/include/mlir/Dialect/Utils/Utils.h

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ constexpr auto TOLERANCE = 1e-15;
2828
* @param parameter The parameter as a variant (double or Value).
2929
* @return Value The parameter as a Value.
3030
*/
31-
inline Value variantToValue(OpBuilder& builder, const OperationState& state,
32-
const std::variant<double, Value>& parameter) {
31+
[[nodiscard]] inline Value
32+
variantToValue(OpBuilder& builder, const OperationState& state,
33+
const std::variant<double, Value>& parameter) {
3334
Value operand;
3435
if (std::holds_alternative<double>(parameter)) {
3536
operand = builder.create<arith::ConstantOp>(
@@ -40,4 +41,32 @@ inline Value variantToValue(OpBuilder& builder, const OperationState& state,
4041
return operand;
4142
}
4243

44+
/**
45+
* @brief Try to convert a mlir::Value to a standard C++ double
46+
*
47+
* @details
48+
* Resolving the mlir::Value will only work if it is a static value, so a value
49+
* defined via a "arith.constant" operation. It must also be of type
50+
* float or integer.
51+
*/
52+
[[nodiscard]] inline std::optional<double> valueToDouble(Value value) {
53+
auto constantOp = value.getDefiningOp<arith::ConstantOp>();
54+
if (!constantOp) {
55+
return std::nullopt;
56+
}
57+
auto floatAttr = dyn_cast<FloatAttr>(constantOp.getValue());
58+
if (floatAttr) {
59+
return floatAttr.getValueAsDouble();
60+
}
61+
auto intAttr = dyn_cast<IntegerAttr>(constantOp.getValue());
62+
if (intAttr) {
63+
if (intAttr.getType().isUnsignedInteger()) {
64+
return static_cast<double>(intAttr.getValue().getZExtValue());
65+
}
66+
// interpret both signed+signless as signed integers
67+
return static_cast<double>(intAttr.getValue().getSExtValue());
68+
}
69+
return std::nullopt;
70+
}
71+
4372
} // namespace mlir::utils

mlir/lib/Dialect/QCO/IR/Operations/StandardGates/GPhaseOp.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
#include <cmath>
1515
#include <mlir/IR/Builders.h>
16-
#include <mlir/IR/BuiltinAttributes.h>
1716
#include <mlir/IR/MLIRContext.h>
1817
#include <mlir/IR/OperationSupport.h>
1918
#include <mlir/IR/PatternMatch.h>
@@ -34,13 +33,8 @@ struct RemoveTrivialGPhase final : OpRewritePattern<GPhaseOp> {
3433

3534
LogicalResult matchAndRewrite(GPhaseOp op,
3635
PatternRewriter& rewriter) const override {
37-
const auto thetaAttr = GPhaseOp::getStaticParameter(op.getTheta());
38-
if (!thetaAttr) {
39-
return failure();
40-
}
41-
42-
const auto thetaValue = thetaAttr.getValueAsDouble();
43-
if (std::abs(thetaValue) > TOLERANCE) {
36+
const auto theta = valueToDouble(op.getTheta());
37+
if (!theta || std::abs(*theta) > TOLERANCE) {
4438
return failure();
4539
}
4640

mlir/lib/Dialect/QCO/IR/Operations/StandardGates/ROp.cpp

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
#include <cmath>
1515
#include <mlir/IR/Builders.h>
16-
#include <mlir/IR/BuiltinAttributes.h>
1716
#include <mlir/IR/MLIRContext.h>
1817
#include <mlir/IR/OperationSupport.h>
1918
#include <mlir/IR/PatternMatch.h>
@@ -35,13 +34,8 @@ struct ReplaceRWithRX final : OpRewritePattern<ROp> {
3534

3635
LogicalResult matchAndRewrite(ROp op,
3736
PatternRewriter& rewriter) const override {
38-
const auto phi = ROp::getStaticParameter(op.getPhi());
39-
if (!phi) {
40-
return failure();
41-
}
42-
43-
const auto phiValue = phi.getValueAsDouble();
44-
if (std::abs(phiValue) > TOLERANCE) {
37+
const auto phi = valueToDouble(op.getPhi());
38+
if (!phi || std::abs(*phi) > TOLERANCE) {
4539
return failure();
4640
}
4741

@@ -61,13 +55,8 @@ struct ReplaceRWithRY final : OpRewritePattern<ROp> {
6155

6256
LogicalResult matchAndRewrite(ROp op,
6357
PatternRewriter& rewriter) const override {
64-
const auto phi = ROp::getStaticParameter(op.getPhi());
65-
if (!phi) {
66-
return failure();
67-
}
68-
69-
const auto phiValue = phi.getValueAsDouble();
70-
if (std::abs(phiValue - (std::numbers::pi / 2.0)) > TOLERANCE) {
58+
const auto phi = valueToDouble(op.getPhi());
59+
if (!phi || std::abs(*phi - (std::numbers::pi / 2.0)) > TOLERANCE) {
7160
return failure();
7261
}
7362

mlir/lib/Dialect/QCO/IR/Operations/StandardGates/U2Op.cpp

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,10 @@ struct ReplaceU2WithH final : OpRewritePattern<U2Op> {
3434

3535
LogicalResult matchAndRewrite(U2Op op,
3636
PatternRewriter& rewriter) const override {
37-
const auto phi = U2Op::getStaticParameter(op.getPhi());
38-
const auto lambda = U2Op::getStaticParameter(op.getLambda());
39-
if (!phi || !lambda) {
40-
return failure();
41-
}
42-
43-
const auto phiValue = phi.getValueAsDouble();
44-
const auto lambdaValue = lambda.getValueAsDouble();
45-
if (std::abs(phiValue) > TOLERANCE ||
46-
std::abs(lambdaValue - std::numbers::pi) > TOLERANCE) {
37+
const auto phi = valueToDouble(op.getPhi());
38+
const auto lambda = valueToDouble(op.getLambda());
39+
if (!phi || std::abs(*phi) > TOLERANCE || !lambda ||
40+
std::abs(*lambda - std::numbers::pi) > TOLERANCE) {
4741
return failure();
4842
}
4943

@@ -62,16 +56,10 @@ struct ReplaceU2WithRX final : OpRewritePattern<U2Op> {
6256

6357
LogicalResult matchAndRewrite(U2Op op,
6458
PatternRewriter& rewriter) const override {
65-
const auto phi = U2Op::getStaticParameter(op.getPhi());
66-
const auto lambda = U2Op::getStaticParameter(op.getLambda());
67-
if (!phi || !lambda) {
68-
return failure();
69-
}
70-
71-
const auto phiValue = phi.getValueAsDouble();
72-
const auto lambdaValue = lambda.getValueAsDouble();
73-
if (std::abs(phiValue + (std::numbers::pi / 2.0)) > TOLERANCE ||
74-
std::abs(lambdaValue - (std::numbers::pi / 2.0)) > TOLERANCE) {
59+
const auto phi = valueToDouble(op.getPhi());
60+
const auto lambda = valueToDouble(op.getLambda());
61+
if (!phi || std::abs(*phi + (std::numbers::pi / 2.0)) > TOLERANCE ||
62+
!lambda || std::abs(*lambda - (std::numbers::pi / 2.0)) > TOLERANCE) {
7563
return failure();
7664
}
7765

@@ -91,15 +79,10 @@ struct ReplaceU2WithRY final : OpRewritePattern<U2Op> {
9179

9280
LogicalResult matchAndRewrite(U2Op op,
9381
PatternRewriter& rewriter) const override {
94-
const auto phi = U2Op::getStaticParameter(op.getPhi());
95-
const auto lambda = U2Op::getStaticParameter(op.getLambda());
96-
if (!phi || !lambda) {
97-
return failure();
98-
}
99-
100-
const auto phiValue = phi.getValueAsDouble();
101-
const auto lambdaValue = lambda.getValueAsDouble();
102-
if (std::abs(phiValue) > TOLERANCE || std::abs(lambdaValue) > TOLERANCE) {
82+
const auto phi = valueToDouble(op.getPhi());
83+
const auto lambda = valueToDouble(op.getLambda());
84+
if (!phi || std::abs(*phi) > TOLERANCE || !lambda ||
85+
std::abs(*lambda) > TOLERANCE) {
10386
return failure();
10487
}
10588

mlir/lib/Dialect/QCO/IR/Operations/StandardGates/UOp.cpp

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
#include <cmath>
1515
#include <mlir/IR/Builders.h>
16-
#include <mlir/IR/BuiltinAttributes.h>
1716
#include <mlir/IR/MLIRContext.h>
1817
#include <mlir/IR/OperationSupport.h>
1918
#include <mlir/IR/PatternMatch.h>
@@ -35,15 +34,10 @@ struct ReplaceUWithP final : OpRewritePattern<UOp> {
3534

3635
LogicalResult matchAndRewrite(UOp op,
3736
PatternRewriter& rewriter) const override {
38-
const auto theta = UOp::getStaticParameter(op.getTheta());
39-
const auto phi = UOp::getStaticParameter(op.getPhi());
40-
if (!theta || !phi) {
41-
return failure();
42-
}
43-
44-
const auto thetaValue = theta.getValueAsDouble();
45-
const auto phiValue = phi.getValueAsDouble();
46-
if (std::abs(thetaValue) > TOLERANCE || std::abs(phiValue) > TOLERANCE) {
37+
const auto theta = valueToDouble(op.getTheta());
38+
const auto phi = valueToDouble(op.getPhi());
39+
if (!theta || std::abs(*theta) > TOLERANCE || !phi ||
40+
std::abs(*phi) > TOLERANCE) {
4741
return failure();
4842
}
4943

@@ -63,16 +57,10 @@ struct ReplaceUWithRX final : OpRewritePattern<UOp> {
6357

6458
LogicalResult matchAndRewrite(UOp op,
6559
PatternRewriter& rewriter) const override {
66-
const auto phi = UOp::getStaticParameter(op.getPhi());
67-
const auto lambda = UOp::getStaticParameter(op.getLambda());
68-
if (!phi || !lambda) {
69-
return failure();
70-
}
71-
72-
const auto phiValue = phi.getValueAsDouble();
73-
const auto lambdaValue = lambda.getValueAsDouble();
74-
if (std::abs(phiValue + (std::numbers::pi / 2.0)) > TOLERANCE ||
75-
std::abs(lambdaValue - (std::numbers::pi / 2.0)) > TOLERANCE) {
60+
const auto phi = valueToDouble(op.getPhi());
61+
const auto lambda = valueToDouble(op.getLambda());
62+
if (!phi || std::abs(*phi + (std::numbers::pi / 2.0)) > TOLERANCE ||
63+
!lambda || std::abs(*lambda - (std::numbers::pi / 2.0)) > TOLERANCE) {
7664
return failure();
7765
}
7866

@@ -92,15 +80,10 @@ struct ReplaceUWithRY final : OpRewritePattern<UOp> {
9280

9381
LogicalResult matchAndRewrite(UOp op,
9482
PatternRewriter& rewriter) const override {
95-
const auto phi = UOp::getStaticParameter(op.getPhi());
96-
const auto lambda = UOp::getStaticParameter(op.getLambda());
97-
if (!phi || !lambda) {
98-
return failure();
99-
}
100-
101-
const auto phiValue = phi.getValueAsDouble();
102-
const auto lambdaValue = lambda.getValueAsDouble();
103-
if (std::abs(phiValue) > TOLERANCE || std::abs(lambdaValue) > TOLERANCE) {
83+
const auto phi = valueToDouble(op.getPhi());
84+
const auto lambda = valueToDouble(op.getLambda());
85+
if (!phi || std::abs(*phi) > TOLERANCE || !lambda ||
86+
std::abs(*lambda) > TOLERANCE) {
10487
return failure();
10588
}
10689

mlir/lib/Dialect/QCO/IR/Operations/StandardGates/XXMinusYYOp.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@ struct MergeSubsequentXXMinusYY final : OpRewritePattern<XXMinusYYOp> {
4747
}
4848

4949
// Confirm betas are equal
50-
auto beta = XXMinusYYOp::getStaticParameter(op.getBeta());
51-
auto prevBeta = XXMinusYYOp::getStaticParameter(prevOp.getBeta());
50+
auto beta = valueToDouble(op.getBeta());
51+
auto prevBeta = valueToDouble(prevOp.getBeta());
5252
if (beta && prevBeta) {
53-
if (std::abs(beta.getValueAsDouble() - prevBeta.getValueAsDouble()) >
54-
TOLERANCE) {
53+
if (std::abs(*beta - *prevBeta) > TOLERANCE) {
5554
return failure();
5655
}
5756
} else if (op.getBeta() != prevOp.getBeta()) {

0 commit comments

Comments
 (0)