Giter Club home page Giter Club logo

Comments (6)

refraction-ray avatar refraction-ray commented on May 24, 2024 1

For now, my preference is to try something like below in furture releases
pip install tensorcircuit # only requires numpy
pip install tensorcircuit[tensorflow] # also install tensorflow

from tensorcircuit.

refraction-ray avatar refraction-ray commented on May 24, 2024 1

And I am also curious about whether it would be convenient for us to re-implement those utilities by uniform API of tc.backend.

It is more than welcome if anyone wants to make these utilities backend agnostic, which is a good first issue. These methods are in

def _id(x: Any) -> Any:
return x
if is_m1mac():
compiled_jit = _id
else:
compiled_jit = partial(get_backend("tensorflow").jit, jit_compile=True)
def heisenberg_hamiltonian(
g: Graph,
hzz: float = 1.0,
hxx: float = 1.0,
hyy: float = 1.0,
hz: float = 0.0,
hx: float = 0.0,
hy: float = 0.0,
sparse: bool = True,
numpy: bool = False,
) -> Tensor:
"""
Generate Heisenberg Hamiltonian with possible external fields.
:Example:
>>> g = tc.templates.graphs.Line1D(6)
>>> h = qu.heisenberg_hamiltonian(g, sparse=False)
>>> tc.backend.eigh(h)[0][:10]
array([-11.2111025, -8.4721365, -8.472136 , -8.472136 , -6. ,
-5.123106 , -5.123106 , -5.1231055, -5.1231055, -5.1231055],
dtype=float32)
:param g: input circuit graph
:type g: Graph
:param hzz: zz coupling, default is 1.0
:type hzz: float
:param hxx: xx coupling, default is 1.0
:type hxx: float
:param hyy: yy coupling, default is 1.0
:type hyy: float
:param hz: External field on z direction, default is 0.0
:type hz: float
:param hx: External field on y direction, default is 0.0
:type hx: float
:param hy: External field on x direction, default is 0.0
:type hy: float
:param sparse: Whether to return sparse Hamiltonian operator, default is True.
:type sparse: bool, defalts True
:param numpy: whether return the matrix in numpy or tensorflow form
:type numpy: bool, defaults False,
:return: Hamiltonian measurements
:rtype: Tensor
"""
n = len(g.nodes)
ls = []
weight = []
for e in g.edges:
if hzz != 0:
r = [0 for _ in range(n)]
r[e[0]] = 3
r[e[1]] = 3
ls.append(r)
weight.append(hzz)
if hxx != 0:
r = [0 for _ in range(n)]
r[e[0]] = 1
r[e[1]] = 1
ls.append(r)
weight.append(hxx)
if hyy != 0:
r = [0 for _ in range(n)]
r[e[0]] = 2
r[e[1]] = 2
ls.append(r)
weight.append(hyy)
for node in g.nodes:
if hz != 0:
r = [0 for _ in range(n)]
r[node] = 3
ls.append(r)
weight.append(hz)
if hx != 0:
r = [0 for _ in range(n)]
r[node] = 1
ls.append(r)
weight.append(hx)
if hy != 0:
r = [0 for _ in range(n)]
r[node] = 2
ls.append(r)
weight.append(hy)
ls = tf.constant(ls)
weight = tf.constant(weight)
ls = get_backend("tensorflow").cast(ls, dtypestr)
weight = get_backend("tensorflow").cast(weight, dtypestr)
if sparse:
r = PauliStringSum2COO_numpy(ls, weight)
if numpy:
return r
return backend.coo_sparse_matrix_from_numpy(r)
return PauliStringSum2Dense(ls, weight, numpy=numpy)
def PauliStringSum2Dense(
ls: Sequence[Sequence[int]],
weight: Optional[Sequence[float]] = None,
numpy: bool = False,
) -> Tensor:
"""
Generate dense matrix from Pauli string sum
:param ls: 2D Tensor, each row is for a Pauli string,
e.g. [1, 0, 0, 3, 2] is for :math:`X_0Z_3Y_4`
:type ls: Sequence[Sequence[int]]
:param weight: 1D Tensor, each element corresponds the weight for each Pauli string
defaults to None (all Pauli strings weight 1.0)
:type weight: Optional[Sequence[float]], optional
:param numpy: default False. If True, return numpy coo
else return backend compatible sparse tensor
:type numpy: bool
:return: the tensorflow dense matrix
:rtype: Tensor
"""
sparsem = PauliStringSum2COO_numpy(ls, weight)
if numpy:
return sparsem.todense()
sparsem = backend.coo_sparse_matrix_from_numpy(sparsem)
densem = backend.to_dense(sparsem)
return densem
# already implemented as backend method
#
# def _tf2numpy_sparse(a: Tensor) -> Tensor:
# return get_backend("numpy").coo_sparse_matrix(
# indices=a.indices,
# values=a.values,
# shape=a.get_shape(),
# )
# def _numpy2tf_sparse(a: Tensor) -> Tensor:
# return get_backend("tensorflow").coo_sparse_matrix(
# indices=np.array([a.row, a.col]).T,
# values=a.data,
# shape=a.shape,
# )
def PauliStringSum2COO(
ls: Sequence[Sequence[int]],
weight: Optional[Sequence[float]] = None,
numpy: bool = False,
) -> Tensor:
"""
Generate sparse tensor from Pauli string sum
:param ls: 2D Tensor, each row is for a Pauli string,
e.g. [1, 0, 0, 3, 2] is for :math:`X_0Z_3Y_4`
:type ls: Sequence[Sequence[int]]
:param weight: 1D Tensor, each element corresponds the weight for each Pauli string
defaults to None (all Pauli strings weight 1.0)
:type weight: Optional[Sequence[float]], optional
:param numpy: default False. If True, return numpy coo
else return backend compatible sparse tensor
:type numpy: bool
:return: the scipy coo sparse matrix
:rtype: Tensor
"""
# numpy version is 3* faster!
nterms = len(ls)
n = len(ls[0])
s = 0b1 << n
if weight is None:
weight = [1.0 for _ in range(nterms)]
if not (isinstance(weight, tf.Tensor) or isinstance(weight, tf.Variable)):
weight = tf.constant(weight, dtype=getattr(tf, dtypestr))
rsparse = get_backend("numpy").coo_sparse_matrix(
indices=np.array([[0, 0]], dtype=np.int64),
values=np.array([0.0], dtype=getattr(np, dtypestr)), # type: ignore
shape=(s, s),
)
for i in range(nterms):
rsparse += get_backend("tensorflow").numpy(PauliString2COO(ls[i], weight[i])) # type: ignore
# auto transformed into csr format!!
rsparse = rsparse.tocoo()
if numpy:
return rsparse
return backend.coo_sparse_matrix_from_numpy(rsparse)
PauliStringSum2COO_numpy = partial(PauliStringSum2COO, numpy=True)
def PauliStringSum2COO_tf(
ls: Sequence[Sequence[int]], weight: Optional[Sequence[float]] = None
) -> Tensor:
"""
Generate tensorflow sparse matrix from Pauli string sum
:param ls: 2D Tensor, each row is for a Pauli string,
e.g. [1, 0, 0, 3, 2] is for :math:`X_0Z_3Y_4`
:type ls: Sequence[Sequence[int]]
:param weight: 1D Tensor, each element corresponds the weight for each Pauli string
defaults to None (all Pauli strings weight 1.0)
:type weight: Optional[Sequence[float]], optional
:return: the tensorflow coo sparse matrix
:rtype: Tensor
"""
nterms = len(ls)
n = len(ls[0])
s = 0b1 << n
if weight is None:
weight = [1.0 for _ in range(nterms)]
if not (isinstance(weight, tf.Tensor) or isinstance(weight, tf.Variable)):
weight = tf.constant(weight, dtype=getattr(tf, dtypestr))
rsparse = tf.SparseTensor(
indices=tf.constant([[0, 0]], dtype=tf.int64),
values=tf.constant([0.0], dtype=weight.dtype), # type: ignore
dense_shape=(s, s),
)
for i in range(nterms):
rsparse = tf.sparse.add(rsparse, PauliString2COO(ls[i], weight[i])) # type: ignore
# very slow sparse.add?
return rsparse
@compiled_jit
def PauliString2COO(l: Sequence[int], weight: Optional[float] = None) -> Tensor:
"""
Generate tensorflow sparse matrix from Pauli string sum
:param l: 1D Tensor representing for a Pauli string,
e.g. [1, 0, 0, 3, 2] is for :math:`X_0Z_3Y_4`
:type l: Sequence[int]
:param weight: the weight for the Pauli string
defaults to None (all Pauli strings weight 1.0)
:type weight: Optional[float], optional
:return: the tensorflow sparse matrix
:rtype: Tensor
"""
n = len(l)
one = tf.constant(0b1, dtype=tf.int64)
idx_x = tf.constant(0b0, dtype=tf.int64)
idx_y = tf.constant(0b0, dtype=tf.int64)
idx_z = tf.constant(0b0, dtype=tf.int64)
i = tf.constant(0, dtype=tf.int64)
for j in l:
# i, j from enumerate is python, non jittable when cond using tensor
if j == 1: # xi
idx_x += tf.bitwise.left_shift(one, n - i - 1)
elif j == 2: # yi
idx_y += tf.bitwise.left_shift(one, n - i - 1)
elif j == 3: # zi
idx_z += tf.bitwise.left_shift(one, n - i - 1)
i += 1
if weight is None:
weight = tf.constant(1.0, dtype=tf.complex64)
return ps2coo_core(idx_x, idx_y, idx_z, weight, n)
@compiled_jit
def ps2coo_core(
idx_x: Tensor, idx_y: Tensor, idx_z: Tensor, weight: Tensor, nqubits: int
) -> Tuple[Tensor, Tensor]:
dtype = weight.dtype
s = 0b1 << nqubits
idx1 = tf.cast(tf.range(s), dtype=tf.int64)
idx2 = (idx1 ^ idx_x) ^ (idx_y)
indices = tf.transpose(tf.stack([idx1, idx2]))
tmp = idx1 & (idx_y | idx_z)
e = idx1 * 0
ny = 0
for i in range(nqubits):
# if tmp[i] is power of 2 (non zero), then e[i] = 1
e ^= tf.bitwise.right_shift(tmp, i) & 0b1
# how many 1 contained in idx_y
ny += tf.bitwise.right_shift(idx_y, i) & 0b1
ny = tf.math.mod(ny, 4)
values = (
tf.cast((1 - 2 * e), dtype)
* tf.math.pow(tf.constant(-1.0j, dtype=dtype), tf.cast(ny, dtype))
* weight
)
return tf.SparseTensor(indices=indices, values=values, dense_shape=(s, s)) # type: ignore
except (NameError, ImportError):

from tensorcircuit.

refraction-ray avatar refraction-ray commented on May 24, 2024

A very good question. Apart from the slow downloading due to the large size, TensorFlow as a requirement has other issues, too. Say in m1 mac, the package name is tensorflow-macos, which can lead to installation failure of tensorcircuit silently.

However, there are several reasons that support the inclusion of tensorflow as a requirement,

  1. some function utilities are now supported solely by tensorflow backend, such as tc.quantum.heisenberg_hamiltonian.
  2. if there is no requirement of tensorflow, then no backend with automatic differentiation is enabled by default which may confuse the users especially for newcomers. Namely, one need to manually install many things to make tensorcircuit work as expected. (this point is the main reason that I keep tensorflow as a requirement because I don't want to scare new users away by failure after pip install tensorcircuit)

Still, to remove or not to remove tf as a requirement, is an question to me. Not sure which side is better, and would love to listen to more feedbacks.

from tensorcircuit.

royess avatar royess commented on May 24, 2024

2. if there is no requirement of tensorflow, then no backend with automatic differentiation is enabled by default which may confuse the users especially for newcomers. Namely, one need to manually install many things to make tensorcircuit work as expected. (this point is the main reason that I keep tensorflow as a requirement because I don't want to scare new users away by failure after pip install tensorcircuit)

For the second point, how about changing the installation guide to the following lines?

pip install tensorflow
pip install tensorcircuit

I suppose it will not be less friendly for new users.

from tensorcircuit.

royess avatar royess commented on May 24, 2024
  1. some function utilities are now supported solely by tensorflow backend, such as tc.quantum.heisenberg_hamiltonian.

And I am also curious about whether it would be convenient for us to re-implement those utilities by uniform API of tc.backend.

from tensorcircuit.

refraction-ray avatar refraction-ray commented on May 24, 2024

closed, as the remaining issue is separately open in #161

from tensorcircuit.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.