Format with Black

This commit is contained in:
tankya2
2023-08-17 13:23:29 +08:00
parent 3fafe2b3ff
commit 89bdbfbe68
3 changed files with 89 additions and 77 deletions

View File

@@ -1,5 +1,6 @@
from cuquantum import contract, contract_path, CircuitToEinsum, tensor from cuquantum import contract, contract_path, CircuitToEinsum, tensor
class MPSContractionHelper: class MPSContractionHelper:
""" """
A helper class to compute various quantities for a given MPS. A helper class to compute various quantities for a given MPS.
@@ -33,9 +34,11 @@ class MPSContractionHelper:
def __init__(self, num_qubits): def __init__(self, num_qubits):
self.num_qubits = num_qubits self.num_qubits = num_qubits
self.bra_modes = [(2*i, 2*i+1, 2*i+2) for i in range(num_qubits)] self.bra_modes = [(2 * i, 2 * i + 1, 2 * i + 2) for i in range(num_qubits)]
offset = 2*num_qubits+1 offset = 2 * num_qubits + 1
self.ket_modes = [(i+offset, 2*i+1, i+1+offset) for i in range(num_qubits)] self.ket_modes = [
(i + offset, 2 * i + 1, i + 1 + offset) for i in range(num_qubits)
]
def contract_norm(self, mps_tensors, options=None): def contract_norm(self, mps_tensors, options=None):
""" """
@@ -52,8 +55,10 @@ class MPSContractionHelper:
""" """
interleaved_inputs = [] interleaved_inputs = []
for i, o in enumerate(mps_tensors): for i, o in enumerate(mps_tensors):
interleaved_inputs.extend([o, self.bra_modes[i], o.conj(), self.ket_modes[i]]) interleaved_inputs.extend(
interleaved_inputs.append([]) # output [o, self.bra_modes[i], o.conj(), self.ket_modes[i]]
)
interleaved_inputs.append([]) # output
return self._contract(interleaved_inputs, options=options).real return self._contract(interleaved_inputs, options=options).real
def contract_state_vector(self, mps_tensors, options=None): def contract_state_vector(self, mps_tensors, options=None):
@@ -73,10 +78,12 @@ class MPSContractionHelper:
for i, o in enumerate(mps_tensors): for i, o in enumerate(mps_tensors):
interleaved_inputs.extend([o, self.bra_modes[i]]) interleaved_inputs.extend([o, self.bra_modes[i]])
output_modes = tuple([bra_modes[1] for bra_modes in self.bra_modes]) output_modes = tuple([bra_modes[1] for bra_modes in self.bra_modes])
interleaved_inputs.append(output_modes) # output interleaved_inputs.append(output_modes) # output
return self._contract(interleaved_inputs, options=options) return self._contract(interleaved_inputs, options=options)
def contract_expectation(self, mps_tensors, operator, qubits, options=None, normalize=False): def contract_expectation(
self, mps_tensors, operator, qubits, options=None, normalize=False
):
""" """
Contract the corresponding tensor network to form the state vector representation of the MPS. Contract the corresponding tensor network to form the state vector representation of the MPS.
@@ -105,11 +112,11 @@ class MPSContractionHelper:
if i in qubits: if i in qubits:
k_modes = (k_modes[0], extra_mode, k_modes[2]) k_modes = (k_modes[0], extra_mode, k_modes[2])
q = qubits.index(i) q = qubits.index(i)
operator_modes[q] = extra_mode # output modes operator_modes[q] = extra_mode # output modes
extra_mode += 1 extra_mode += 1
interleaved_inputs.extend([o.conj(), k_modes]) interleaved_inputs.extend([o.conj(), k_modes])
interleaved_inputs.extend([operator, tuple(operator_modes)]) interleaved_inputs.extend([operator, tuple(operator_modes)])
interleaved_inputs.append([]) # output interleaved_inputs.append([]) # output
if normalize: if normalize:
norm = self.contract_norm(mps_tensors, options=options) norm = self.contract_norm(mps_tensors, options=options)
else: else:
@@ -117,7 +124,6 @@ class MPSContractionHelper:
return self._contract(interleaved_inputs, options=options) / norm return self._contract(interleaved_inputs, options=options) / norm
def _contract(self, interleaved_inputs, options=None): def _contract(self, interleaved_inputs, options=None):
path = contract_path(*interleaved_inputs, options=options)[0] path = contract_path(*interleaved_inputs, options=options)[0]
return contract(*interleaved_inputs, options=options, optimize={'path':path}) return contract(*interleaved_inputs, options=options, optimize={"path": path})

View File

@@ -2,33 +2,32 @@ import cupy as cp
from cuquantum.cutensornet.experimental import contract_decompose from cuquantum.cutensornet.experimental import contract_decompose
from cuquantum import contract from cuquantum import contract
def initial(num_qubits, dtype): def initial(num_qubits, dtype):
""" """
Generate the MPS with an initial state of |00...00> Generate the MPS with an initial state of |00...00>
""" """
state_tensor = cp.asarray([1, 0], dtype=dtype).reshape(1,2,1) state_tensor = cp.asarray([1, 0], dtype=dtype).reshape(1, 2, 1)
mps_tensors = [state_tensor] * num_qubits mps_tensors = [state_tensor] * num_qubits
return mps_tensors return mps_tensors
def mps_site_right_swap(
mps_tensors, def mps_site_right_swap(mps_tensors, i, **kwargs):
i,
**kwargs
):
""" """
Perform the swap operation between the ith and i+1th MPS tensors. Perform the swap operation between the ith and i+1th MPS tensors.
""" """
# contraction followed by QR decomposition # contraction followed by QR decomposition
a, _, b = contract_decompose('ipj,jqk->iqj,jpk', *mps_tensors[i:i+2], algorithm=kwargs.get('algorithm',None), options=kwargs.get('options',None)) a, _, b = contract_decompose(
mps_tensors[i:i+2] = (a, b) "ipj,jqk->iqj,jpk",
*mps_tensors[i : i + 2],
algorithm=kwargs.get("algorithm", None),
options=kwargs.get("options", None)
)
mps_tensors[i : i + 2] = (a, b)
return mps_tensors return mps_tensors
def apply_gate(
mps_tensors, def apply_gate(mps_tensors, gate, qubits, **kwargs):
gate,
qubits,
**kwargs
):
""" """
Apply the gate operand to the MPS tensors in-place. Apply the gate operand to the MPS tensors in-place.
@@ -52,23 +51,31 @@ def apply_gate(
if n_qubits == 1: if n_qubits == 1:
# single-qubit gate # single-qubit gate
i = qubits[0] i = qubits[0]
mps_tensors[i] = contract('ipj,qp->iqj', mps_tensors[i], gate, options=kwargs.get('options',None)) # in-place update mps_tensors[i] = contract(
"ipj,qp->iqj", mps_tensors[i], gate, options=kwargs.get("options", None)
) # in-place update
elif n_qubits == 2: elif n_qubits == 2:
# two-qubit gate # two-qubit gate
i, j = qubits i, j = qubits
if i > j: if i > j:
# swap qubits order # swap qubits order
return apply_gate(mps_tensors, gate.transpose(1,0,3,2), (j, i), **kwargs) return apply_gate(mps_tensors, gate.transpose(1, 0, 3, 2), (j, i), **kwargs)
elif i+1 == j: elif i + 1 == j:
# two adjacent qubits # two adjacent qubits
a, _, b = contract_decompose('ipj,jqk,rspq->irj,jsk', *mps_tensors[i:i+2], gate, algorithm=kwargs.get('algorithm',None), options=kwargs.get('options',None)) a, _, b = contract_decompose(
mps_tensors[i:i+2] = (a, b) # in-place update "ipj,jqk,rspq->irj,jsk",
*mps_tensors[i : i + 2],
gate,
algorithm=kwargs.get("algorithm", None),
options=kwargs.get("options", None)
)
mps_tensors[i : i + 2] = (a, b) # in-place update
else: else:
# non-adjacent two-qubit gate # non-adjacent two-qubit gate
# step 1: swap i with i+1 # step 1: swap i with i+1
mps_site_right_swap(mps_tensors, i, **kwargs) mps_site_right_swap(mps_tensors, i, **kwargs)
# step 2: apply gate to (i+1, j) pair. This amounts to a recursive swap until the two qubits are adjacent # step 2: apply gate to (i+1, j) pair. This amounts to a recursive swap until the two qubits are adjacent
apply_gate(mps_tensors, gate, (i+1, j), **kwargs) apply_gate(mps_tensors, gate, (i + 1, j), **kwargs)
# step 3: swap back i and i+1 # step 3: swap back i and i+1
mps_site_right_swap(mps_tensors, i, **kwargs) mps_site_right_swap(mps_tensors, i, **kwargs)
else: else:

View File

@@ -44,8 +44,7 @@ class QiboCircuitToEinsum:
for key in qubits_frontier: for key in qubits_frontier:
out_list.append(qubits_frontier[key]) out_list.append(qubits_frontier[key])
operand_exp_interleave = [x for y in zip( operand_exp_interleave = [x for y in zip(operands, mode_labels) for x in y]
operands, mode_labels) for x in y]
operand_exp_interleave.append(out_list) operand_exp_interleave.append(out_list)
return operand_exp_interleave return operand_exp_interleave