Skip to content

Commit

Permalink
Fix operand types for STORE and classical comparison operators
Browse files Browse the repository at this point in the history
- Allow immediate floats as third arg in prepare_ternary_operands

- Allow immediate values as source arg for STORE and ClassicalStore

- Allow CONVERT to take any valid memory reference designator, i.e. a
MemoryReference, a string, or a tuple of (str, int).

Fixes #815
  • Loading branch information
appleby committed Sep 21, 2019
1 parent 9bdbd71 commit 8b0f5e2
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 16 deletions.
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ Changelog

### Bugfixes

- Strength two symmetrization was not correctly producing orthogonal
arrays due to erroneous truncation, which has been fixed
(@kylegulshen, gh-990).
- Strength two symmetrization was not correctly producing orthogonal arrays due to erroneous
truncation, which has been fixed (@kylegulshen, gh-990).
- The `STORE` instruction now accepts `int` or `float` in addition to `MemoryReference` as it's
`source` argument. As a result, you can now `STORE` an immediate value into a memory register
(@appleby, TBD).
- The `EQ`, `LT`, `LE`, `GT`, and `GE` instructions now all accept `float` in addition to `int` or
`MemoryReference` as their third and final argument. As a result, you can now perform classical
comparisons against an immediate `float` value (@appleby, TBD).
- The `CONVERT` instruction now accepts any valid memory reference designator for both it's
arguments, i.e. a `MemoryReference`, a string, or a tuple of type `(str, int)`.

[v2.11](https://github.com/rigetti/pyquil/compare/v2.10.0...v2.11.0) (September 3, 2019)
----------------------------------------------------------------------------------------
Expand Down
9 changes: 6 additions & 3 deletions pyquil/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def prepare_ternary_operands(classical_reg1, classical_reg2, classical_reg3):
if isinstance(classical_reg2, int):
raise TypeError("Left operand of comparison must be a memory address")
classical_reg2 = unpack_classical_reg(classical_reg2)
if not isinstance(classical_reg3, int):
if not isinstance(classical_reg3, int) and not isinstance(classical_reg3, float):
classical_reg3 = unpack_classical_reg(classical_reg3)

return classical_reg1, classical_reg2, classical_reg3
Expand Down Expand Up @@ -639,6 +639,8 @@ def STORE(region_name, offset_reg, source):
:param source: Source data. Can be either a MemoryReference or a constant.
:return: A ClassicalStore instance.
"""
if not isinstance(source, int) and not isinstance(source, float):
source = unpack_classical_reg(source)
return ClassicalStore(region_name, unpack_classical_reg(offset_reg), source)


Expand All @@ -648,9 +650,10 @@ def CONVERT(classical_reg1, classical_reg2):
:param classical_reg1: MemoryReference to store to.
:param classical_reg2: MemoryReference to read from.
:return: A ClassicalCONVERT instance.
:return: A ClassicalConvert instance.
"""
return ClassicalConvert(classical_reg1, classical_reg2)
return ClassicalConvert(unpack_classical_reg(classical_reg1),
unpack_classical_reg(classical_reg2))


def ADD(classical_reg, right):
Expand Down
5 changes: 3 additions & 2 deletions pyquil/quilbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,8 +736,9 @@ class ClassicalStore(AbstractInstruction):
def __init__(self, target, left, right):
if not isinstance(left, MemoryReference):
raise TypeError("left operand should be an MemoryReference")
if not isinstance(right, MemoryReference):
raise TypeError("right operand should be an MemoryReference")
if not (isinstance(right, MemoryReference) or isinstance(right, int)
or isinstance(right, float)):
raise TypeError("right operand should be an MemoryReference or an int or float.")
self.target = target
self.left = left
self.right = right
Expand Down
21 changes: 21 additions & 0 deletions pyquil/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ def test_memory_commands():
parse_equals("DECLARE mem OCTET[32] SHARING mem2 OFFSET 16 REAL OFFSET 32 REAL",
Declare("mem", "OCTET", 32, shared_region="mem2", offsets=[(16, "REAL"), (32, "REAL")]))
parse_equals("STORE mem ro[2] ro[0]", STORE("mem", MemoryReference("ro", 2), MemoryReference("ro", 0)))
parse_equals("STORE mem ro[2] 7", STORE("mem", MemoryReference("ro", 2), 7))
parse_equals("LOAD ro[8] mem mem[4]", LOAD(MemoryReference("ro", 8), "mem", MemoryReference("mem", 4)))
parse_equals("CONVERT ro[1] ro[2]", CONVERT(MemoryReference("ro", 1), MemoryReference("ro", 2)))
parse_equals("EXCHANGE ro[0] ro[1]", EXCHANGE(MemoryReference("ro", 0), MemoryReference("ro", 1)))
Expand Down Expand Up @@ -236,6 +237,26 @@ def test_classical():
GT(MemoryReference("comp", 1), MemoryReference("ro", 3), MemoryReference("ro", 2)))
parse_equals("GE comp[1] ro[3] ro[2]",
GE(MemoryReference("comp", 1), MemoryReference("ro", 3), MemoryReference("ro", 2)))
parse_equals("EQ comp[1] ro[3] 0",
EQ(MemoryReference("comp", 1), MemoryReference("ro", 3), 0))
parse_equals("LT comp[1] ro[3] 1",
LT(MemoryReference("comp", 1), MemoryReference("ro", 3), 1))
parse_equals("LE comp[1] ro[3] 2",
LE(MemoryReference("comp", 1), MemoryReference("ro", 3), 2))
parse_equals("GT comp[1] ro[3] 3",
GT(MemoryReference("comp", 1), MemoryReference("ro", 3), 3))
parse_equals("GE comp[1] ro[3] 4",
GE(MemoryReference("comp", 1), MemoryReference("ro", 3), 4))
parse_equals("EQ comp[1] ro[3] 0.0",
EQ(MemoryReference("comp", 1), MemoryReference("ro", 3), 0.0))
parse_equals("LT comp[1] ro[3] 1.1",
LT(MemoryReference("comp", 1), MemoryReference("ro", 3), 1.1))
parse_equals("LE comp[1] ro[3] 2.2",
LE(MemoryReference("comp", 1), MemoryReference("ro", 3), 2.2))
parse_equals("GT comp[1] ro[3] 3.3",
GT(MemoryReference("comp", 1), MemoryReference("ro", 3), 3.3))
parse_equals("GE comp[1] ro[3] 4.4",
GE(MemoryReference("comp", 1), MemoryReference("ro", 3), 4.4))


def test_pragma():
Expand Down
66 changes: 58 additions & 8 deletions pyquil/tests/test_quil.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -247,22 +247,72 @@ def test_binary_classicals():
'EXCHANGE ro[0] ro[1]\n'


def test_memory_reference_unpacking():
p = Program()

p.inst(AND("ro", ("ro", 1)),
MOVE("ro", ("ro", 1)),
CONVERT("ro", ("ro", 1)),
IOR("ro", ("ro", 1)),
XOR("ro", ("ro", 1)),
ADD("ro", ("ro", 1)),
SUB("ro", ("ro", 1)),
MUL("ro", ("ro", 1)),
DIV("ro", ("ro", 1)),
EXCHANGE("ro", ("ro", 1)))

assert p.out() == 'AND ro[0] ro[1]\n' \
'MOVE ro[0] ro[1]\n' \
'CONVERT ro[0] ro[1]\n' \
'IOR ro[0] ro[1]\n' \
'XOR ro[0] ro[1]\n' \
'ADD ro[0] ro[1]\n' \
'SUB ro[0] ro[1]\n'\
'MUL ro[0] ro[1]\n' \
'DIV ro[0] ro[1]\n' \
'EXCHANGE ro[0] ro[1]\n'


def test_ternary_classicals():
p = Program()
p.inst(LOAD(MemoryReference("ro", 0), "ro", MemoryReference("n", 0)),
STORE("ro", MemoryReference("n", 0), MemoryReference("ro", 0)),
EQ(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 2)),
STORE("ro", MemoryReference("n", 0), 0),
STORE("ro", MemoryReference("n", 0), 0.1),
EQ(MemoryReference("ro", 0), MemoryReference("ro", 1), 0),
EQ(MemoryReference("ro", 0), MemoryReference("ro", 1), 0.0),
EQ(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 0)),
GE(MemoryReference("ro", 0), MemoryReference("ro", 1), 1),
GE(MemoryReference("ro", 0), MemoryReference("ro", 1), 1.1),
GE(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 1)),
GT(MemoryReference("ro", 0), MemoryReference("ro", 1), 2),
GT(MemoryReference("ro", 0), MemoryReference("ro", 1), 2.2),
GT(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 2)),
GE(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 2)),
LE(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 2)),
LT(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 2)))
LE(MemoryReference("ro", 0), MemoryReference("ro", 1), 3),
LE(MemoryReference("ro", 0), MemoryReference("ro", 1), 3.3),
LE(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 3)),
LT(MemoryReference("ro", 0), MemoryReference("ro", 1), 4),
LT(MemoryReference("ro", 0), MemoryReference("ro", 1), 4.4),
LT(MemoryReference("ro", 0), MemoryReference("ro", 1), MemoryReference("ro", 4)))
assert p.out() == 'LOAD ro[0] ro n[0]\n' \
'STORE ro n[0] ro[0]\n' \
'EQ ro[0] ro[1] ro[2]\n' \
'STORE ro n[0] 0\n' \
'STORE ro n[0] 0.1\n' \
'EQ ro[0] ro[1] 0\n' \
'EQ ro[0] ro[1] 0.0\n' \
'EQ ro[0] ro[1] ro[0]\n' \
'GE ro[0] ro[1] 1\n' \
'GE ro[0] ro[1] 1.1\n' \
'GE ro[0] ro[1] ro[1]\n' \
'GT ro[0] ro[1] 2\n' \
'GT ro[0] ro[1] 2.2\n' \
'GT ro[0] ro[1] ro[2]\n' \
'GE ro[0] ro[1] ro[2]\n' \
'LE ro[0] ro[1] ro[2]\n' \
'LT ro[0] ro[1] ro[2]\n'
'LE ro[0] ro[1] 3\n' \
'LE ro[0] ro[1] 3.3\n' \
'LE ro[0] ro[1] ro[3]\n' \
'LT ro[0] ro[1] 4\n' \
'LT ro[0] ro[1] 4.4\n' \
'LT ro[0] ro[1] ro[4]\n'


def test_measurement_calls():
Expand Down

0 comments on commit 8b0f5e2

Please sign in to comment.