|
36 | 36 | "shift_left", |
37 | 37 | "shift_right", |
38 | 38 | "index", |
| 39 | + "add", |
| 40 | + "sub", |
| 41 | + "mul", |
| 42 | + "div", |
39 | 43 | "lift_legacy_condition", |
40 | 44 | ] |
41 | 45 |
|
@@ -564,3 +568,209 @@ def index(target: typing.Any, index: typing.Any, /) -> Expr: |
564 | 568 | if target.type.kind is not types.Uint or index.type.kind is not types.Uint: |
565 | 569 | raise TypeError(f"invalid types for indexing: '{target.type}' and '{index.type}'") |
566 | 570 | return Index(target, index, types.Bool()) |
| 571 | + |
| 572 | + |
| 573 | +def _binary_sum(op: Binary.Op, left: typing.Any, right: typing.Any) -> Expr: |
| 574 | + left, right = _lift_binary_operands(left, right) |
| 575 | + if left.type.kind is right.type.kind and left.type.kind in { |
| 576 | + types.Uint, |
| 577 | + types.Float, |
| 578 | + types.Duration, |
| 579 | + }: |
| 580 | + type = types.greater(left.type, right.type) |
| 581 | + return Binary( |
| 582 | + op, |
| 583 | + _coerce_lossless(left, type), |
| 584 | + _coerce_lossless(right, type), |
| 585 | + type, |
| 586 | + ) |
| 587 | + raise TypeError(f"invalid types for '{op}': '{left.type}' and '{right.type}'") |
| 588 | + |
| 589 | + |
| 590 | +def add(left: typing.Any, right: typing.Any, /) -> Expr: |
| 591 | + """Create an addition expression node from the given values, resolving any implicit casts and |
| 592 | + lifting the values into :class:`Value` nodes if required. |
| 593 | +
|
| 594 | + Examples: |
| 595 | + Addition of two floating point numbers:: |
| 596 | +
|
| 597 | + >>> from qiskit.circuit.classical import expr |
| 598 | + >>> expr.add(5.0, 2.0) |
| 599 | + Binary(\ |
| 600 | +Binary.Op.ADD, \ |
| 601 | +Value(5.0, Float()), \ |
| 602 | +Value(2.0, Float()), \ |
| 603 | +Float()) |
| 604 | +
|
| 605 | + Addition of two durations:: |
| 606 | +
|
| 607 | + >>> from qiskit.circuit import Duration |
| 608 | + >>> from qiskit.circuit.classical import expr |
| 609 | + >>> expr.add(Duration.dt(1000), Duration.dt(1000)) |
| 610 | + Binary(\ |
| 611 | +Binary.Op.ADD, \ |
| 612 | +Value(Duration.dt(1000), Duration()), \ |
| 613 | +Value(Duration.dt(1000), Duration()), \ |
| 614 | +Duration()) |
| 615 | + """ |
| 616 | + return _binary_sum(Binary.Op.ADD, left, right) |
| 617 | + |
| 618 | + |
| 619 | +def sub(left: typing.Any, right: typing.Any, /) -> Expr: |
| 620 | + """Create a subtraction expression node from the given values, resolving any implicit casts and |
| 621 | + lifting the values into :class:`Value` nodes if required. |
| 622 | +
|
| 623 | + Examples: |
| 624 | + Subtraction of two floating point numbers:: |
| 625 | +
|
| 626 | + >>> from qiskit.circuit.classical import expr |
| 627 | + >>> expr.sub(5.0, 2.0) |
| 628 | + Binary(\ |
| 629 | +Binary.Op.SUB, \ |
| 630 | +Value(5.0, Float()), \ |
| 631 | +Value(2.0, Float()), \ |
| 632 | +Float()) |
| 633 | +
|
| 634 | + Subtraction of two durations:: |
| 635 | +
|
| 636 | + >>> from qiskit.circuit import Duration |
| 637 | + >>> from qiskit.circuit.classical import expr |
| 638 | + >>> expr.add(Duration.dt(1000), Duration.dt(1000)) |
| 639 | + Binary(\ |
| 640 | +Binary.Op.SUB, \ |
| 641 | +Value(Duration.dt(1000), Duration()), \ |
| 642 | +Value(Duration.dt(1000), Duration()), \ |
| 643 | +Duration()) |
| 644 | + """ |
| 645 | + return _binary_sum(Binary.Op.SUB, left, right) |
| 646 | + |
| 647 | + |
| 648 | +def mul(left: typing.Any, right: typing.Any) -> Expr: |
| 649 | + """Create a multiplication expression node from the given values, resolving any implicit casts and |
| 650 | + lifting the values into :class:`Value` nodes if required. |
| 651 | +
|
| 652 | + This can be used to multiply numeric operands of the same type kind, or to multiply a duration |
| 653 | + operand by a numeric operand. |
| 654 | +
|
| 655 | + Examples: |
| 656 | + Multiplication of two floating point numbers:: |
| 657 | +
|
| 658 | + >>> from qiskit.circuit.classical import expr |
| 659 | + >>> expr.mul(5.0, 2.0) |
| 660 | + Binary(\ |
| 661 | +Binary.Op.MUL, \ |
| 662 | +Value(5.0, Float()), \ |
| 663 | +Value(2.0, Float()), \ |
| 664 | +Float()) |
| 665 | +
|
| 666 | + Multiplication of a duration by a float:: |
| 667 | +
|
| 668 | + >>> from qiskit.circuit import Duration |
| 669 | + >>> from qiskit.circuit.classical import expr |
| 670 | + >>> expr.mul(Duration.dt(1000), 0.5) |
| 671 | + Binary(\ |
| 672 | +Binary.Op.MUL, \ |
| 673 | +Value(Duration.dt(1000), Duration()), \ |
| 674 | +Value(0.5, Float()), \ |
| 675 | +Duration()) |
| 676 | + """ |
| 677 | + left, right = _lift_binary_operands(left, right) |
| 678 | + type: types.Type |
| 679 | + if left.type.kind is right.type.kind is types.Duration: |
| 680 | + raise TypeError("cannot multiply two durations") |
| 681 | + if left.type.kind is right.type.kind and left.type.kind in {types.Uint, types.Float}: |
| 682 | + type = types.greater(left.type, right.type) |
| 683 | + left = _coerce_lossless(left, type) |
| 684 | + right = _coerce_lossless(right, type) |
| 685 | + elif left.type.kind is types.Duration and right.type.kind in {types.Uint, types.Float}: |
| 686 | + if not right.const: |
| 687 | + raise ValueError( |
| 688 | + f"multiplying operands '{left}' and '{right}' would result in a non-const '{left.type}'" |
| 689 | + ) |
| 690 | + type = left.type |
| 691 | + elif right.type.kind is types.Duration and left.type.kind in {types.Uint, types.Float}: |
| 692 | + if not left.const: |
| 693 | + raise ValueError( |
| 694 | + f"multiplying operands '{left}' and '{right}' would result in a non-const '{right.type}'" |
| 695 | + ) |
| 696 | + type = right.type |
| 697 | + else: |
| 698 | + raise TypeError(f"invalid types for '{Binary.Op.MUL}': '{left.type}' and '{right.type}'") |
| 699 | + return Binary( |
| 700 | + Binary.Op.MUL, |
| 701 | + left, |
| 702 | + right, |
| 703 | + type, |
| 704 | + ) |
| 705 | + |
| 706 | + |
| 707 | +def div(left: typing.Any, right: typing.Any) -> Expr: |
| 708 | + """Create a division expression node from the given values, resolving any implicit casts and |
| 709 | + lifting the values into :class:`Value` nodes if required. |
| 710 | +
|
| 711 | + This can be used to divide numeric operands of the same type kind, to divide a |
| 712 | + :class`~.types.Duration` operand by a numeric operand, or to divide two |
| 713 | + :class`~.types.Duration` operands which yields an expression of type |
| 714 | + :class:`~.types.Float`. |
| 715 | +
|
| 716 | + Examples: |
| 717 | + Division of two floating point numbers:: |
| 718 | +
|
| 719 | + >>> from qiskit.circuit.classical import expr |
| 720 | + >>> expr.div(5.0, 2.0) |
| 721 | + Binary(\ |
| 722 | +Binary.Op.DIV, \ |
| 723 | +Value(5.0, Float()), \ |
| 724 | +Value(2.0, Float()), \ |
| 725 | +Float()) |
| 726 | +
|
| 727 | + Division of two durations:: |
| 728 | +
|
| 729 | + >>> from qiskit.circuit import Duration |
| 730 | + >>> from qiskit.circuit.classical import expr |
| 731 | + >>> expr.div(Duration.dt(10000), Duration.dt(1000)) |
| 732 | + Binary(\ |
| 733 | +Binary.Op.DIV, \ |
| 734 | +Value(Duration.dt(10000), Duration()), \ |
| 735 | +Value(Duration.dt(1000), Duration()), \ |
| 736 | +Float()) |
| 737 | +
|
| 738 | +
|
| 739 | + Division of a duration by a float:: |
| 740 | +
|
| 741 | + >>> from qiskit.circuit import Duration |
| 742 | + >>> from qiskit.circuit.classical import expr |
| 743 | + >>> expr.div(Duration.dt(10000), 12.0) |
| 744 | + Binary(\ |
| 745 | +Binary.Op.DIV, \ |
| 746 | +Value(Duration.dt(10000), Duration()), \ |
| 747 | +Value(12.0, types.Float()), \ |
| 748 | +Duration()) |
| 749 | + """ |
| 750 | + left, right = _lift_binary_operands(left, right) |
| 751 | + type: types.Type |
| 752 | + if left.type.kind is right.type.kind and left.type.kind in { |
| 753 | + types.Duration, |
| 754 | + types.Uint, |
| 755 | + types.Float, |
| 756 | + }: |
| 757 | + if left.type.kind is types.Duration: |
| 758 | + type = types.Float() |
| 759 | + elif types.order(left.type, right.type) is not types.Ordering.NONE: |
| 760 | + type = types.greater(left.type, right.type) |
| 761 | + left = _coerce_lossless(left, type) |
| 762 | + right = _coerce_lossless(right, type) |
| 763 | + elif left.type.kind is types.Duration and right.type.kind in {types.Uint, types.Float}: |
| 764 | + if not right.const: |
| 765 | + raise ValueError( |
| 766 | + f"division of '{left}' and '{right}' would result in a non-const '{left.type}'" |
| 767 | + ) |
| 768 | + type = left.type |
| 769 | + else: |
| 770 | + raise TypeError(f"invalid types for '{Binary.Op.DIV}': '{left.type}' and '{right.type}'") |
| 771 | + return Binary( |
| 772 | + Binary.Op.DIV, |
| 773 | + left, |
| 774 | + right, |
| 775 | + type, |
| 776 | + ) |
0 commit comments