Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support qiskit2tq to parse Qiskit’s ParameterExpression #275

Conversation

king-p3nguin
Copy link

@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
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
Author

Tests are now added.

@01110011011101010110010001101111
Copy link
Collaborator

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

@king-p3nguin
Copy link
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
5 of 7 checks passed
@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