Repository: rigetticomputing/pyquil
Pull request #291 (2018-02-03 20:11:27)

Fix/paramater quil names
Fixes issue #258 .

stevenheidel: @mstechly - thanks for the PR! Just a couple style fixes to complete before we can merge this, take a look at the semaphore build:
```
pyquil/tests/test_parameters.py:5:93: W291 trailing whitespace
pyquil/tests/test_parameters.py:6:33: E127 continuation line over-indented for visual indent
```
mstechly: @stevenheidel Thanks, I will pay more attention to the semaphore next time.

Patch:
diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst
index ff1674a..ffd2e23 100644
--- a/docs/source/getting_started.rst
+++ b/docs/source/getting_started.rst
@@ -518,10 +518,7 @@ matrix representation of the gate. For example, below we define a
 
 
 
-Quil in general supports defining parametric gates, though right now
-only static gates are supported by pyQuil. Below we show how we can
-define :math:`X_0\otimes \sqrt{X_1}` as a single
-gate.
+Below we show how we can define :math:`X_0\otimes \sqrt{X_1}` as a single gate.
 
 .. code:: python
 
@@ -545,6 +542,41 @@ gate.
     (0.5+0.5j)|01> + (0.5-0.5j)|11>
 
 
+
+Defining Parametric Gates
+~~~~~~~~~~~~~~~~~~
+
+It is also possible to define parametric gates using pyQuil.
+Let's say we want to have a controlled RX gate. Since RX is a parametric gate, we need a slightly different way of defining it than in the previous section.
+
+.. code:: python
+
+    from pyquil.parameters import Parameter, quil_sin, quil_cos
+    from pyquil.quilbase import DefGate
+    import numpy as np
+
+    theta = Parameter('theta')
+    crx = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, quil_cos(theta / 2), -1j * quil_sin(theta / 2)], [0, 0, -1j * quil_sin(theta / 2), quil_cos(theta / 2)]])
+    
+    dg = DefGate('CRX', crx, [theta])
+    CRX = dg.get_constructor()
+
+    p = Program()
+    p.inst(dg)
+    p.inst(H(0))
+    p.inst(CRX(np.pi/2)(0, 1))
+
+    wavefunction = qvm.wavefunction(p)
+    print(wavefunction)
+
+
+.. parsed-literal::
+
+    (0.7071067812+0j)|00> + (0.5+0j)|01> + -0.5j|11>
+
+``quil_sin`` and ``quil_cos`` work as the regular sinus and cosinus, but they support the parametrization. Parametrized functions you can use with pyQuil are: ``quil_sin``, ``quil_cos``, ``quil_sqrt``, ``quil_exp``, and ``quil_cis``.
+
+
 Advanced Usage
 --------------
 
diff --git a/pyquil/_parser/PyQuilListener.py b/pyquil/_parser/PyQuilListener.py
index 738a5c5..d44661d 100644
--- a/pyquil/_parser/PyQuilListener.py
+++ b/pyquil/_parser/PyQuilListener.py
@@ -292,15 +292,15 @@ def _apply_function(func, arg):
     # type: (QuilParser.FunctionContext, Any) -> Any
     if isinstance(arg, Expression):
         if func.SIN():
-            return parameters.sin(arg)
+            return parameters.quil_sin(arg)
         elif func.COS():
-            return parameters.cos(arg)
+            return parameters.quil_cos(arg)
         elif func.SQRT():
-            return parameters.sqrt(arg)
+            return parameters.quil_sqrt(arg)
         elif func.EXP():
-            return parameters.exp(arg)
+            return parameters.quil_exp(arg)
         elif func.CIS():
-            return parameters.cis(arg)
+            return parameters.quil_cis(arg)
         else:
             raise RuntimeError("Unexpected function to apply: " + func.getText())
     else:
diff --git a/pyquil/parameters.py b/pyquil/parameters.py
index 6860032..51e5808 100644
--- a/pyquil/parameters.py
+++ b/pyquil/parameters.py
@@ -6,7 +6,7 @@ from six import integer_types
 from pyquil.quilatom import QuilAtom
 from pyquil.slot import Slot
 
-__all__ = ['Parameter', 'sin', 'cos', 'sqrt', 'exp', 'cis']
+__all__ = ['Parameter', 'quil_sin', 'quil_cos', 'quil_sqrt', 'quil_exp', 'quil_cis']
 
 
 def format_parameter(element):
@@ -170,23 +170,23 @@ class Function(Expression):
         return not self.__eq__(other)
 
 
-def sin(expression):
+def quil_sin(expression):
     return Function('sin', expression, np.sin)
 
 
-def cos(expression):
+def quil_cos(expression):
     return Function('cos', expression, np.cos)
 
 
-def sqrt(expression):
+def quil_sqrt(expression):
     return Function('sqrt', expression, np.sqrt)
 
 
-def exp(expression):
+def quil_exp(expression):
     return Function('exp', expression, np.exp)
 
 
-def cis(expression):
+def quil_cis(expression):
     return Function('cis', expression, lambda x: np.exp(1j * x))
 
 


Test patch:
diff --git a/pyquil/tests/test_parameters.py b/pyquil/tests/test_parameters.py
index 0e8e395..c9298d2 100644
--- a/pyquil/tests/test_parameters.py
+++ b/pyquil/tests/test_parameters.py
@@ -2,8 +2,8 @@ from math import pi
 
 import numpy as np
 
-from pyquil.parameters import (Parameter, sin, _contained_parameters, format_parameter, sqrt, cis,
-                               exp, cos, substitute, substitute_array)
+from pyquil.parameters import (Parameter, quil_sin, quil_cos, quil_sqrt, quil_exp, quil_cis,
+                               _contained_parameters, format_parameter, quil_cis, substitute, substitute_array)
 
 
 def test_format_parameter():
@@ -58,8 +58,8 @@ def test_expression_to_string():
     assert str(x ** (y ** 2)) == '%x^%y^2'
     assert str((x ** y) ** 2) == '(%x^%y)^2'
 
-    assert str(sin(x)) == 'sin(%x)'
-    assert str(3 * sin(x + y)) == '3*sin(%x+%y)'
+    assert str(quil_sin(x)) == 'sin(%x)'
+    assert str(3 * quil_sin(x + y)) == '3*sin(%x+%y)'
 
 
 def test_contained_parameters():
@@ -69,7 +69,7 @@ def test_contained_parameters():
     y = Parameter('y')
     assert _contained_parameters(x + y) == {x, y}
 
-    assert _contained_parameters(x ** y ** sin(x * y * 4)) == {x, y}
+    assert _contained_parameters(x ** y ** quil_sin(x * y * 4)) == {x, y}
 
 
 def test_eval():
@@ -79,13 +79,13 @@ def test_eval():
     y = Parameter('y')
     assert substitute(x + y, {x: 5, y: 6}) == 11
     assert substitute(x + y, {x: 5}) == 5 + y
-    assert substitute(exp(x), {y: 5}) != exp(5)
-    assert substitute(exp(x), {x: 5}) == np.exp(5)
+    assert substitute(quil_exp(x), {y: 5}) != np.exp(5)
+    assert substitute(quil_exp(x), {x: 5}) == np.exp(5)
 
-    assert np.isclose(substitute(sin(x * x ** 2 / y), {x: 5.0, y: 10.0}), np.sin(12.5))
-    assert np.isclose(substitute(sqrt(x), {x: 5.0, y: 10.0}), np.sqrt(5.0))
-    assert np.isclose(substitute(cis(x), {x: 5.0, y: 10.0}), np.exp(1j * 5.0))
+    assert np.isclose(substitute(quil_sin(x * x ** 2 / y), {x: 5.0, y: 10.0}), np.sin(12.5))
+    assert np.isclose(substitute(quil_sqrt(x), {x: 5.0, y: 10.0}), np.sqrt(5.0))
+    assert np.isclose(substitute(quil_cis(x), {x: 5.0, y: 10.0}), np.exp(1j * 5.0))
     assert np.isclose(substitute(x - y, {x: 5.0, y: 10.0}), -5.)
 
-    assert substitute(cis(x), {y: 5}) == cis(x)
-    assert np.allclose(substitute_array([sin(x), cos(x)], {x: 5}), [np.sin(5), np.cos(5)])
+    assert substitute(quil_cis(x), {y: 5}) == quil_cis(x)
+    assert np.allclose(substitute_array([quil_sin(x), quil_cos(x)], {x: 5}), [np.sin(5), np.cos(5)])
diff --git a/pyquil/tests/test_parser.py b/pyquil/tests/test_parser.py
index 3e77140..66ad72d 100644
--- a/pyquil/tests/test_parser.py
+++ b/pyquil/tests/test_parser.py
@@ -17,7 +17,7 @@ import numpy as np
 import pytest
 
 from pyquil.gates import *
-from pyquil.parameters import Parameter, cos, sin
+from pyquil.parameters import Parameter, quil_sin, quil_cos
 from pyquil.parser import parse
 from pyquil.quilatom import Addr
 from pyquil.quilbase import Label, JumpTarget, Jump, JumpWhen, JumpUnless, DefGate, Qubit, Pragma
@@ -56,8 +56,8 @@ def test_def_gate_with_variables():
     # Note that technically the RX gate includes -i instead of just i but this messes a bit with the test since
     # it's not smart enough to figure out that -1*i == -i
     theta = Parameter('theta')
-    rx = np.array([[cos(theta / 2), 1j * sin(theta / 2)],
-                   [1j * sin(theta / 2), cos(theta / 2)]])
+    rx = np.array([[quil_cos(theta / 2), 1j * quil_sin(theta / 2)],
+                   [1j * quil_sin(theta / 2), quil_cos(theta / 2)]])
 
     defgate = 'DEFGATE RX(%theta):\n' \
               '    cos(%theta/2), i*sin(%theta/2)\n' \
@@ -125,6 +125,7 @@ def test_expressions():
     _expr("sin(0)", 0.0)
     _expr("cos(0)", 1.0)
     _expr("sqrt(4)", 2.0)
+    _expr("exp(0)", 1.0)
     _expr("cis(0)", complex(1, 0))
 
     # Unary precedence
diff --git a/pyquil/tests/test_quil.py b/pyquil/tests/test_quil.py
index 3ed08d5..05ab69d 100644
--- a/pyquil/tests/test_quil.py
+++ b/pyquil/tests/test_quil.py
@@ -23,7 +23,7 @@ import pytest
 from pyquil.gates import I, X, Y, Z, H, T, S, RX, RY, RZ, CNOT, CCNOT, PHASE, CPHASE00, CPHASE01, \
     CPHASE10, CPHASE, SWAP, CSWAP, ISWAP, PSWAP, MEASURE, HALT, WAIT, NOP, RESET, \
     TRUE, FALSE, NOT, AND, OR, MOVE, EXCHANGE
-from pyquil.parameters import Parameter, cos, sin
+from pyquil.parameters import Parameter, quil_sin, quil_cos
 from pyquil.quil import Program, merge_programs, shift_quantum_gates
 from pyquil.quilbase import DefGate, Gate, Addr, Qubit, JumpWhen
 
@@ -313,8 +313,8 @@ def test_def_gate():
 
 def test_def_gate_with_parameters():
     theta = Parameter('theta')
-    rx = np.array([[cos(theta / 2), -1j * sin(theta / 2)],
-                   [-1j * sin(theta / 2), cos(theta / 2)]])
+    rx = np.array([[quil_cos(theta / 2), -1j * quil_sin(theta / 2)],
+                   [-1j * quil_sin(theta / 2), quil_cos(theta / 2)]])
 
     p = Program().defgate("RX", rx, [theta])
     assert p.out() == 'DEFGATE RX(%theta):\n' \