code: def as_scipy_operator(op):
      
      # Lazy import to improve `import odl` time
      import scipy.sparse
  
      if not op.is_linear:
          raise ValueError('`op` needs to be linear')
  
      dtype = op.domain.dtype
      if op.range.dtype != dtype:
          raise ValueError('dtypes of ``op.domain`` and ``op.range`` needs to '
                           'match')
  
      shape = (native(op.range.size), native(op.domain.size))
  
      def matvec(v):
          return (op(v.reshape(op.domain.shape))).asarray().ravel()
  
      def rmatvec(v):
          return (op.adjoint(v.reshape(op.range.shape))).asarray().ravel()
  
      return scipy.sparse.linalg.LinearOperator(shape=shape,
                                                matvec=matvec,
                                                rmatvec=rmatvec,
                                                dtype=dtype)
docs: Wrap ``op`` as a ``scipy.sparse.linalg.LinearOperator``.
  
      This is intended to be used with the scipy sparse linear solvers.
  
      Parameters
      ----------
      op : `Operator`
          A linear operator that should be wrapped
  
      Returns
      -------
      ``scipy.sparse.linalg.LinearOperator`` : linear_op
          The wrapped operator, has attributes ``matvec`` which calls ``op``,
          and ``rmatvec`` which calls ``op.adjoint``.
  
      Examples
      --------
      Wrap operator and solve simple problem (here toy problem ``Ix = b``)
  
      >>> op = odl.IdentityOperator(odl.rn(3))
      >>> scipy_op = as_scipy_operator(op)
      >>> import scipy.sparse.linalg as scipy_solvers
      >>> result, status = scipy_solvers.cg(scipy_op, [0, 1, 0])
      >>> result
      array([ 0.,  1.,  0.])
  
      Notes
      -----
      If the data representation of ``op``'s domain and range is of type
      `NumpyTensorSpace` this incurs no significant overhead. If the space
      type is ``CudaFn`` or some other nonlocal type, the overhead is
      significant.