Skip to content

Commit 530ccef

Browse files
committed
Test the new solver
1 parent 8b2ed66 commit 530ccef

1 file changed

Lines changed: 147 additions & 0 deletions

File tree

mlir/unittests/DecompGraphSolver/Test_DecompGraphSolver.cpp

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,3 +546,150 @@ TEST_CASE("Test OperatorNode equality with staticNamedArgs", "[DecompGraph::Core
546546
REQUIRE(pauliRotX == pauliRotX2);
547547
REQUIRE_FALSE(pauliRotX == pauliRotY);
548548
}
549+
550+
////////////////
551+
// Adjoint Tests
552+
////////////////
553+
554+
TEST_CASE("Self-adjoint Adjoint(H) -> H", "[DecompGraph::Solver]") {
555+
const OperatorNode h{"H[][1]{}", "Hadamard"};
556+
const OperatorNode adjH{"Adjoint(H[][1]{})", "Adjoint(Hadamard)"};
557+
558+
const WeightedGateset gateset{{{h.name, 1.0}}};
559+
const std::vector<RuleNode> rules{
560+
{"adj_h_to_h", adjH, {{h, 1}}},
561+
};
562+
563+
const DecompositionGraph graph({adjH}, gateset, rules);
564+
DecompositionSolver solver(graph);
565+
const auto result = solver.solve();
566+
567+
const auto &chosen = result.at(adjH);
568+
REQUIRE_FALSE(chosen.isBasis);
569+
REQUIRE(chosen.ruleName == "adj_h_to_h");
570+
REQUIRE(chosen.totalCost == 1.0);
571+
REQUIRE(result.at(h).isBasis);
572+
}
573+
574+
TEST_CASE("Adjoint(RZ) -> RZ resolves at RZ's cost", "[DecompGraph::Solver]") {
575+
const OperatorNode rz{"RZ[f64][1]{}", "RZ"};
576+
const OperatorNode adjRz{"Adjoint(RZ[f64][1]{})", "Adjoint(RZ)"};
577+
578+
const WeightedGateset gateset{{{rz.name, 4.0}}};
579+
const std::vector<RuleNode> rules{
580+
{"adj_rz_to_rz", adjRz, {{rz, 1}}},
581+
};
582+
583+
const DecompositionGraph graph({adjRz}, gateset, rules);
584+
DecompositionSolver solver(graph);
585+
const auto result = solver.solve();
586+
587+
const auto &chosen = result.at(adjRz);
588+
REQUIRE_FALSE(chosen.isBasis);
589+
REQUIRE(chosen.ruleName == "adj_rz_to_rz");
590+
REQUIRE(chosen.totalCost == 4.0);
591+
REQUIRE(result.at(rz).isBasis);
592+
}
593+
594+
TEST_CASE("Adjoint(Rot) -> Adjoint(RZ) Adjoint(RY) Adjoint(RZ)", "[DecompGraph::Solver]") {
595+
const OperatorNode rz{"RZ[f64][1]{}", "RZ"};
596+
const OperatorNode ry{"RY[f64][1]{}", "RY"};
597+
const OperatorNode adjRz{"Adjoint(RZ[f64][1]{})", "Adjoint(RZ)"};
598+
const OperatorNode adjRy{"Adjoint(RY[f64][1]{})", "Adjoint(RY)"};
599+
const OperatorNode adjRot{"Adjoint(Rot[f64,f64,f64][1]{})", "Adjoint(Rot)"};
600+
601+
const WeightedGateset gateset{{{rz.name, 1.0}, {ry.name, 2.0}}};
602+
const std::vector<RuleNode> rules{
603+
{"adj_rot_distribute", adjRot, {{adjRz, 2}, {adjRy, 1}}},
604+
{"adj_rz_to_rz", adjRz, {{rz, 1}}},
605+
{"adj_ry_to_ry", adjRy, {{ry, 1}}},
606+
};
607+
608+
const DecompositionGraph graph({adjRot}, gateset, rules);
609+
DecompositionSolver solver(graph);
610+
const auto result = solver.solve();
611+
612+
const auto &chosen = result.at(adjRot);
613+
REQUIRE_FALSE(chosen.isBasis);
614+
REQUIRE(chosen.ruleName == "adj_rot_distribute");
615+
REQUIRE(chosen.totalCost == 4.0);
616+
617+
REQUIRE_FALSE(result.at(adjRz).isBasis);
618+
REQUIRE(result.at(adjRz).ruleName == "adj_rz_to_rz");
619+
REQUIRE_FALSE(result.at(adjRy).isBasis);
620+
REQUIRE(result.at(adjRy).ruleName == "adj_ry_to_ry");
621+
REQUIRE(result.at(rz).isBasis);
622+
REQUIRE(result.at(ry).isBasis);
623+
}
624+
625+
TEST_CASE("Competing adjoint pathways are picked by cost", "[DecompGraph::Solver]") {
626+
const OperatorNode rz{"RZ[f64][1]{}", "RZ"};
627+
const OperatorNode ry{"RY[f64][1]{}", "RY"};
628+
const OperatorNode adjRz{"Adjoint(RZ[f64][1]{})", "Adjoint(RZ)"};
629+
const OperatorNode adjRy{"Adjoint(RY[f64][1]{})", "Adjoint(RY)"};
630+
const OperatorNode adjRot{"Adjoint(Rot[f64,f64,f64][1]{})", "Adjoint(Rot)"};
631+
632+
const WeightedGateset gateset{{{rz.name, 1.0}, {ry.name, 2.0}}};
633+
634+
const RuleNode distribute{"adj_rot_distribute", adjRot, {{adjRz, 2}, {adjRy, 1}}};
635+
const RuleNode adjRzToRz{"adj_rz_to_rz", adjRz, {{rz, 1}}};
636+
const RuleNode adjRyToRy{"adj_ry_to_ry", adjRy, {{ry, 1}}};
637+
638+
SECTION("dedicated pathway wins when it is cheaper") {
639+
const RuleNode dedicated{"adj_rot_dedicated", adjRot, {{rz, 1}}}; // cost 1 < 4
640+
const DecompositionGraph graph({adjRot}, gateset,
641+
{dedicated, distribute, adjRzToRz, adjRyToRy});
642+
DecompositionSolver solver(graph);
643+
const auto result = solver.solve();
644+
REQUIRE(result.at(adjRot).ruleName == "adj_rot_dedicated");
645+
REQUIRE(result.at(adjRot).totalCost == 1.0);
646+
}
647+
648+
SECTION("distribution pathway wins when the dedicated rule is more expensive") {
649+
const RuleNode dedicated{"adj_rot_dedicated", adjRot, {{rz, 10}}}; // cost 10 > 4
650+
const DecompositionGraph graph({adjRot}, gateset,
651+
{dedicated, distribute, adjRzToRz, adjRyToRy});
652+
DecompositionSolver solver(graph);
653+
const auto result = solver.solve();
654+
REQUIRE(result.at(adjRot).ruleName == "adj_rot_distribute");
655+
REQUIRE(result.at(adjRot).totalCost == 4.0);
656+
}
657+
}
658+
659+
TEST_CASE("A non-adjoint decomposition can produce an adjoint input", "[DecompGraph::Solver]") {
660+
const OperatorNode h{"H[][1]{}", "Hadamard"};
661+
const OperatorNode cnot{"CNOT[][2]{}", "CNOT"};
662+
const OperatorNode phaseShift{"PhaseShift[f64][1]{}", "PhaseShift"};
663+
const OperatorNode adjT{"Adjoint(T[][1]{})", "Adjoint(T)"};
664+
const OperatorNode myGate{"MyGate[][1]{}", "MyGate"};
665+
666+
const WeightedGateset gateset{{{h.name, 1.0}, {cnot.name, 5.0}, {phaseShift.name, 1.0}}};
667+
const std::vector<RuleNode> rules{
668+
{"mygate_decomp", myGate, {{h, 1}, {adjT, 1}, {cnot, 1}}}, // emits an Adjoint(T)
669+
{"adj_t_to_phaseshift", adjT, {{phaseShift, 1}}},
670+
};
671+
672+
const DecompositionGraph graph({myGate}, gateset, rules);
673+
DecompositionSolver solver(graph);
674+
const auto result = solver.solve();
675+
676+
REQUIRE(result.at(myGate).ruleName == "mygate_decomp");
677+
REQUIRE_FALSE(result.at(adjT).isBasis);
678+
REQUIRE(result.at(adjT).ruleName == "adj_t_to_phaseshift");
679+
REQUIRE(result.at(phaseShift).isBasis);
680+
REQUIRE(result.at(h).isBasis);
681+
REQUIRE(result.at(cnot).isBasis);
682+
}
683+
684+
TEST_CASE("Adjoint of an invalid target fails instead of collapsing to the base",
685+
"[DecompGraph::Solver]") {
686+
const OperatorNode measure{"M[][1]{}", "Measure"};
687+
const OperatorNode adjMeasure{"Adjoint(M[][1]{})", "Adjoint(Measure)"};
688+
689+
const WeightedGateset gateset{{{measure.name, 1.0}}};
690+
const std::vector<RuleNode> rules{};
691+
692+
const DecompositionGraph graph({adjMeasure}, gateset, rules);
693+
DecompositionSolver solver(graph);
694+
REQUIRE_THROWS_AS(solver.solve(), GraphSolverFailedError);
695+
}

0 commit comments

Comments
 (0)