prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Get rid of netket::Ising and other hard-coded hamiltonians in c++
  In the spirit of #199 , we can safely remove the Ising and Heisenberg hamiltonians from the C++ classes, since those are nothing but specific cases of more general hamiltonians (basically they are just LocalOperators or even GraphOperator). 
  Convenient constructors can be defined in few lines of python, and moved to the python part of the library. 
  
  The BoseHubbard hamiltonian is a bit trickier, we can keep it as it is for the moment. 
  
  </issue>
  <code>
  [start of netket/operator.py]
  1 from ._C_netket.operator import *
  2
  [end of netket/operator.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/netket/operator.py b/netket/operator.py
  --- a/netket/operator.py
  +++ b/netket/operator.py
  @@ -1 +1,52 @@
   from ._C_netket.operator import *
  +import numpy as _np
  +
  +
  +def Ising(hilbert, h, J=1.0):
  +    """
  +    Constructs a new ``Ising`` given a hilbert space, a transverse field,
  +    and (if specified) a coupling constant.
  +
  +    Args:
  +        hilbert: Hilbert space the operator acts on.
  +        h: The strength of the transverse field.
  +        J: The strength of the coupling. Default is 1.0.
  +
  +    Examples:
  +        Constructs an ``Ising`` operator for a 1D system.
  +
  +        ```python
  +        >>> import netket as nk
  +        >>> g = nk.graph.Hypercube(length=20, n_dim=1, pbc=True)
  +        >>> hi = nk.hilbert.Spin(s=0.5, graph=g)
  +        >>> op = nk.operator.Ising(h=1.321, hilbert=hi, J=0.5)
  +        >>> print(op.hilbert.size)
  +        20
  +    """
  +    sigma_x = _np.array([[0, 1], [1, 0]])
  +    sz_sz = _np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
  +    return GraphOperator(hilbert, siteops=[-h * sigma_x], bondops=[J * sz_sz])
  +
  +
  +def Heisenberg(hilbert):
  +    """
  +    Constructs a new ``Heisenberg`` given a hilbert space.
  +    Args:
  +        hilbert: Hilbert space the operator acts on.
  +    Examples:
  +     Constructs a ``Heisenberg`` operator for a 1D system.
  +        ```python
  +        >>> import netket as nk
  +        >>> g = nk.graph.Hypercube(length=20, n_dim=1, pbc=True)
  +        >>> hi = nk.hilbert.Spin(s=0.5, total_sz=0, graph=g)
  +        >>> op = nk.operator.Heisenberg(hilbert=hi)
  +        >>> print(op.hilbert.size)
  +        20
  +    """
  +    sz_sz = _np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
  +    exchange = _np.array([[0, 0, 0, 0], [0, 0, 2, 0], [0, 2, 0, 0], [0, 0, 0, 0]])
  +    if hilbert.graph.is_bipartite:
  +        heis_term = sz_sz - exchange
  +    else:
  +        heis_term = sz_sz + exchange
  +    return GraphOperator(hilbert, bondops=[heis_term])
  
verification_info: {"golden_diff": "diff --git a/netket/operator.py b/netket/operator.py\n--- a/netket/operator.py\n+++ b/netket/operator.py\n@@ -1 +1,52 @@\n from ._C_netket.operator import *\n+import numpy as _np\n+\n+\n+def Ising(hilbert, h, J=1.0):\n+    \"\"\"\n+    Constructs a new ``Ising`` given a hilbert space, a transverse field,\n+    and (if specified) a coupling constant.\n+\n+    Args:\n+        hilbert: Hilbert space the operator acts on.\n+        h: The strength of the transverse field.\n+        J: The strength of the coupling. Default is 1.0.\n+\n+    Examples:\n+        Constructs an ``Ising`` operator for a 1D system.\n+\n+        ```python\n+        >>> import netket as nk\n+        >>> g = nk.graph.Hypercube(length=20, n_dim=1, pbc=True)\n+        >>> hi = nk.hilbert.Spin(s=0.5, graph=g)\n+        >>> op = nk.operator.Ising(h=1.321, hilbert=hi, J=0.5)\n+        >>> print(op.hilbert.size)\n+        20\n+    \"\"\"\n+    sigma_x = _np.array([[0, 1], [1, 0]])\n+    sz_sz = _np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])\n+    return GraphOperator(hilbert, siteops=[-h * sigma_x], bondops=[J * sz_sz])\n+\n+\n+def Heisenberg(hilbert):\n+    \"\"\"\n+    Constructs a new ``Heisenberg`` given a hilbert space.\n+    Args:\n+        hilbert: Hilbert space the operator acts on.\n+    Examples:\n+     Constructs a ``Heisenberg`` operator for a 1D system.\n+        ```python\n+        >>> import netket as nk\n+        >>> g = nk.graph.Hypercube(length=20, n_dim=1, pbc=True)\n+        >>> hi = nk.hilbert.Spin(s=0.5, total_sz=0, graph=g)\n+        >>> op = nk.operator.Heisenberg(hilbert=hi)\n+        >>> print(op.hilbert.size)\n+        20\n+    \"\"\"\n+    sz_sz = _np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])\n+    exchange = _np.array([[0, 0, 0, 0], [0, 0, 2, 0], [0, 2, 0, 0], [0, 0, 0, 0]])\n+    if hilbert.graph.is_bipartite:\n+        heis_term = sz_sz - exchange\n+    else:\n+        heis_term = sz_sz + exchange\n+    return GraphOperator(hilbert, bondops=[heis_term])\n", "issue": "Get rid of netket::Ising and other hard-coded hamiltonians in c++\nIn the spirit of #199 , we can safely remove the Ising and Heisenberg hamiltonians from the C++ classes, since those are nothing but specific cases of more general hamiltonians (basically they are just LocalOperators or even GraphOperator). \r\nConvenient constructors can be defined in few lines of python, and moved to the python part of the library. \r\n\r\nThe BoseHubbard hamiltonian is a bit trickier, we can keep it as it is for the moment. \n", "before_files": [{"content": "from ._C_netket.operator import *\n", "path": "netket/operator.py"}]}