jcmgray / quimb

A python library for quantum information and many-body calculations including tensor networks.
http://quimb.readthedocs.io
Other
455 stars 107 forks source link

Customizing parametrized tensors #115

Open yuxuanzhang1995 opened 2 years ago

yuxuanzhang1995 commented 2 years ago

Hi, when constructing a TN with psi.gate_(), is it possible customize your tensor? (e.g., fix off diagonal terms or define certain functions in the tensor) Thanks!

jcmgray commented 2 years ago

Hi, I'm not totally sure I understand this question - with the gate function you can apply an arbitrary array already. Maybe you could give some more specific details?

yuxuanzhang1995 commented 2 years ago

Yeah, let’s say if I want to implement something like:

T = np.zeros([2,2])
T[0][0] = np.exp((J+h))
T[1][0] = np.exp(-1*(J))
T[0][1] = np.exp(-1*(J))
T[1][1] = np.exp((J-h))

where J and h are parameters; can I do that? Thanks!

On Mar 28, 2022, at 12:32 PM, Johnnie Gray @.***> wrote:

Hi, I'm not totally sure I understand this question - with the gate function you can apply an arbitrary array already. Maybe you could give some more specific details?

— Reply to this email directly, view it on GitHub https://github.com/jcmgray/quimb/issues/115#issuecomment-1080946456, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANRXQL7PW3QZBJ4EH5BVHFDVCHUJPANCNFSM5RX36EVA. You are receiving this because you authored the thread.

jcmgray commented 2 years ago

I think you're already there! just call psi.gate_(T, where) now?

jcmgray commented 2 years ago

Oh I think I didn't parse the parametrized in the title of this issue, is the aim to optimize the TN w.r.t to the parameters, and thus you need PTensor instances?

In which case have a look in circuit.py at how this is achieved for the preset gates. e.g.:

https://github.com/jcmgray/quimb/blob/28dc9dd222001b4336e33a147ad4bb442cb38455/quimb/tensor/circuit.py#L382-L411

that implements the function in a autoray compatible way (so many backends can be used), and creates a parametrized array which you could then optimize with respect to.

However, if you just want to construct the TN and contract it e.g., then the parametrized machinery is not necessary.

yuxuanzhang1995 commented 2 years ago

Yeah that’s exactly what I needed. Thanks for the reference!

On Mar 28, 2022, at 3:57 PM, Johnnie Gray @.***> wrote:

Oh I think I didn't parse the parametrized in the title of this issue, is the aim to optimize the TN w.r.t to the parameters, and thus you need PTensor instances?

In which case have a look in circuit.py at how this is achieved for the preset gates. e.g.:

https://github.com/jcmgray/quimb/blob/28dc9dd222001b4336e33a147ad4bb442cb38455/quimb/tensor/circuit.py#L382-L411 https://github.com/jcmgray/quimb/blob/28dc9dd222001b4336e33a147ad4bb442cb38455/quimb/tensor/circuit.py#L382-L411 that implements the function in a autoray compatible way (so many backends can be used), and creates a parametrized array which you could then optimize with respect to.

However, if you just want to construct the TN and contract it e.g., then the parametrized machinery is not necessary.

— Reply to this email directly, view it on GitHub https://github.com/jcmgray/quimb/issues/115#issuecomment-1081136273, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANRXQLZQUPYGIHVSQKU5TA3VCIMM7ANCNFSM5RX36EVA. You are receiving this because you authored the thread.

ghost commented 2 years ago

Hi @jcmgray, I'm trying to create a custom parameterised gate for applying to a quantum circuit. I have tried to copy how 'fsim' is implemented in circuit.py:

...
def Givens_param_gen(theta): 

    a = do('cos', theta) 
    b = do('sin', theta) 

    data = [[1, 0, 0, 0], 
            [0, a, -b, 0], 
            [0, b, a, 0], 
            [0, 0, 0, 1]] 

    return ops.asarray(data) 

def apply_Givens(psi, theta, i, j, parametrize=False, **gate_opts): 
    mtags = _merge_tags('GIVENS', gate_opts) 
    if parametrize: 
        G = ops.PArray(Givens_param_gen, theta) 
    #else:
    #    qu.Givens(theta)
    psi.gate_(G, (int(i), int(j)), tags=mtags, **gate_opts)

from quimb.tensor.circuit import GATE_FUNCTIONS, ONE_QUBIT_PARAM_GATES, TWO_QUBIT_PARAM_GATES, ALL_PARAM_GATES
GATE_FUNCTIONS['GIVENS'] = apply_Givens
TWO_QUBIT_PARAM_GATES.add('GIVENS')
ALL_PARAM_GATES = ONE_QUBIT_PARAM_GATES | TWO_QUBIT_PARAM_GATES

def W_circ(n, **kwargs):

    circ = qtn.Circuit(n, **kwargs)

    circ.apply_gate('GIVENS', *qu.randn(1, dist='uniform'), 0, 1, parametrize=True)

    return circ
...

After plugging this into a loss-function/optimizer, the apply_gate is causing the error ValueError: The gate 'GIVENS' cannot be parametrized., I tried to solve this by explicitly adding 'GIVENS' to ALL_PARAM_GATES, but this didn't work. Am I missing something?

jcmgray commented 2 years ago

This line:

ALL_PARAM_GATES = ONE_QUBIT_PARAM_GATES | TWO_QUBIT_PARAM_GATES

redefines ALL_PARAM_GATES locally, not within circuit.py. It should work if you modify the circuit.py source (feel free to submit a PR with the new gate too), or you modify the variable inplace with ALL_PARAM_GATES.add('GIVENS').

Long term it might be worth adding adding an API so that we can add more custom gates easily.

jcmgray commented 2 years ago

As of https://github.com/jcmgray/quimb/commit/576edce8d58e1e69d882b64c3938b58a0711c62d, you should be able to just use:

def givens_param_gen(theta): 

    a = do('cos', theta) 
    b = do('sin', theta) 

    data = [[1, 0, 0, 0], 
            [0, a, -b, 0], 
            [0, b, a, 0], 
            [0, 0, 0, 1]] 

    return ops.asarray(data) 

register_param_gate('GIVENS', givens_param_gen, num_qubits=2)

I'd happily accept a PR adding this gate to quimb proper if you thought that would be useful.

yuxuanzhang1995 commented 1 year ago

Oh, sorry; I guess the question is: does the autodiff part apply to customed functions like this?

On Mar 28, 2022, at 3:46 PM, Johnnie Gray @.***> wrote:

psi.gate_

jcmgray commented 1 year ago

Yes, any part of quimb that uses autoray.do like above supports autodiff.