Skip to content

Support qiskit2tq to parse Qiskit’s ParameterExpression#275

Merged
01110011011101010110010001101111 merged 7 commits intomit-han-lab:unitary-hackfrom
king-p3nguin:qiskit2tq-parameterexpression
Jun 13, 2024
Merged

Support qiskit2tq to parse Qiskit’s ParameterExpression#275
01110011011101010110010001101111 merged 7 commits intomit-han-lab:unitary-hackfrom
king-p3nguin:qiskit2tq-parameterexpression

Conversation

@king-p3nguin
Copy link
Copy Markdown

@king-p3nguin king-p3nguin commented Jun 6, 2024

Resolve #263

Details

  • I used sympy.lambdify to parse Qiskit's ParameterExpression. Any kind of ParameterExpression can be used as long as Qiskit or Sympy supports the expression. (See following example)
  • I will wait until Make TQ Compatible with Qiskit ≥1.0.0 #267 is merged because I have not checked whether it still works with qiskit>=1.0.0.

Example (based on train_state_prep.py)

import torch
import torch.optim as optim

import torchquantum as tq
from torch.optim.lr_scheduler import CosineAnnealingLR

import random
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector, Parameter
from torchquantum.plugin import qiskit2tq

ansatz = QuantumCircuit(2)
ansatz_param = Parameter("Θ") # parameter
ansatz.rx(ansatz_param, 0)
ansatz_param_vector = ParameterVector("φ", 9) # parameter vector
ansatz.u(ansatz_param_vector[0], ansatz_param_vector[1], ansatz_param_vector[2], 0)
ansatz.u(
    ansatz_param_vector[3] + ansatz_param_vector[1], # parameter expression
    ansatz_param_vector[4] * ansatz_param_vector[2],
    ansatz_param_vector[5] / ansatz_param_vector[0],
    1,
)
ansatz.cu(
    np.sin(ansatz_param_vector[6]), # numpy functions
    np.abs(np.sin(ansatz_param_vector[7])), # nested numpy functions
    # complex expression
    np.abs(np.sin(ansatz_param_vector[8])) * np.exp(ansatz_param_vector[1] + ansatz_param_vector[2]),
    0.0,
    0,
    1,
)


def train(target_state, device, model, optimizer):
    model(device)
    result_state = device.get_states_1d()[0]

    # compute the state infidelity
    loss = 1 - torch.dot(result_state, target_state).abs() ** 2

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    print(
        f"infidelity (loss): {loss.item()}, \n target state : "
        f"{target_state.detach().cpu().numpy()}, \n "
        f"result state : {result_state.detach().cpu().numpy()}\n"
    )


seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)

device = torch.device("cpu")
model = qiskit2tq(ansatz).to(device)
print(model)

n_epochs = 10
optimizer = optim.Adam(model.parameters(), lr=1e-2, weight_decay=0)
scheduler = CosineAnnealingLR(optimizer, T_max=n_epochs)

q_device = tq.QuantumDevice(n_wires=2)
target_state = torch.tensor([0, 1, 0, 0], dtype=torch.complex64)

for epoch in range(1, n_epochs + 1):
    print(f"Epoch {epoch}, LR: {optimizer.param_groups[0]['lr']}")
    train(target_state, q_device, model, optimizer)
    scheduler.step()

Output:

QuantumModuleFromOps(
  (ops): QuantumModuleList(
    (0):  class: RX 
     parameters: Parameter containing:
    tensor([[2.4019]], requires_grad=True) 
     wires: [0] 
     inverse: False
    (1):  class: U3 
     parameters: Parameter containing:
    tensor([[ 2.6075, -0.7360,  2.8859]], requires_grad=True) 
     wires: [0] 
     inverse: False
    (2):  class: U3 
     parameters: Parameter containing:
    tensor([[-1.4243,  1.8295, -0.5866]], requires_grad=True) 
     wires: [1] 
     inverse: False
    (3):  class: CU 
     parameters: Parameter containing:
    tensor([[0.9626, 0.3636, 6.3739, 0.0000]], requires_grad=True) 
     wires: [0, 1] 
     inverse: False
  )
)
Epoch 1, LR: 0.01
infidelity (loss): 0.6692649126052856, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.0999714 -0.6586203j  -0.5717409 -0.06202715j  0.29171193+0.07556738j
  0.29684204-0.21579707j]

Epoch 2, LR: 0.009755282581475769
infidelity (loss): 0.6621534824371338, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.09573969-0.6596097j  -0.57720983-0.06837652j  0.28471547+0.07582995j
  0.29304212-0.21264003j]

Epoch 3, LR: 0.009045084971874737
infidelity (loss): 0.6551913022994995, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.09154983-0.6604437j  -0.58290994-0.07088457j  0.27886063+0.07612759j
  0.28773254-0.21041745j]

Epoch 4, LR: 0.007938926261462366
infidelity (loss): 0.6487162113189697, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.08761434-0.6611002j  -0.5879854 -0.07454494j  0.2731675 +0.07628112j
  0.28329697-0.20806299j]

Epoch 5, LR: 0.006545084971874737
infidelity (loss): 0.6430189609527588, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.08412315-0.6615827j  -0.5923966 -0.07776422j  0.26821756+0.07635648j
  0.27936015-0.2060038j ]

Epoch 6, LR: 0.005
infidelity (loss): 0.638312816619873, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.08122104-0.66191393j -0.5960295 -0.08022463j  0.2642149 +0.07638404j
  0.27601   -0.20435348j]

Epoch 7, LR: 0.003454915028125263
infidelity (loss): 0.6347126364707947, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.07899112-0.6621257j  -0.5987737 -0.08220325j  0.2611553 +0.07637724j
  0.27347285-0.20307513j]

Epoch 8, LR: 0.0020610737385376348
infidelity (loss): 0.6322224140167236, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.07744468-0.66225094j -0.60064095-0.08371409j  0.25901985+0.07635573j
  0.2717662 -0.20216379j]

Epoch 9, LR: 0.0009549150281252633
infidelity (loss): 0.6307358741760254, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.07652031-0.662317j   -0.6017321 -0.08475052j  0.25772044+0.07633403j
  0.2707957 -0.20159304j]

Epoch 10, LR: 0.00024471741852423234
infidelity (loss): 0.6300469636917114, 
 target state : [0.+0.j 1.+0.j 0.+0.j 0.+0.j], 
 result state : [-0.07609182-0.66234535j -0.6022414 -0.08519605j  0.25712723+0.07632397j
  0.27033237-0.20133616j]

@01110011011101010110010001101111
Copy link
Copy Markdown
Collaborator

Hello, could you also add tests for the new functionality?

@king-p3nguin king-p3nguin changed the base branch from main to unitary-hack June 7, 2024 01:50
@king-p3nguin
Copy link
Copy Markdown
Author

Tests are now added.

@01110011011101010110010001101111
Copy link
Copy Markdown
Collaborator

@king-p3nguin Merged in the >= 1.0.0 update; can you take a look into fixing these updates?

@king-p3nguin
Copy link
Copy Markdown
Author

@GenericP3rson Thank you for the update. The tests are working now.

@01110011011101010110010001101111 01110011011101010110010001101111 merged commit 91c80de into mit-han-lab:unitary-hack Jun 13, 2024
@king-p3nguin king-p3nguin deleted the qiskit2tq-parameterexpression branch June 13, 2024 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supporting Additional Features for tq2qiskit and qiskit2tq

2 participants