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

Customizing parametrized tensors #115

Open
yuxuanzhang1995 opened this issue Mar 27, 2022 · 10 comments
Open

Customizing parametrized tensors #115

yuxuanzhang1995 opened this issue Mar 27, 2022 · 10 comments

Comments

@yuxuanzhang1995
Copy link

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
Copy link
Owner

jcmgray commented Mar 28, 2022

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
Copy link
Author

yuxuanzhang1995 commented Mar 28, 2022 via email

@jcmgray
Copy link
Owner

jcmgray commented Mar 28, 2022

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

@jcmgray
Copy link
Owner

jcmgray commented Mar 28, 2022

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.:

def fsim_param_gen(params):
theta, phi = params[0], params[1]
a_re = do('cos', theta)
a_im = do('imag', a_re)
a = do('complex', a_re, a_im)
b_im = -do('sin', theta)
b_re = do('imag', b_im)
b = do('complex', b_re, b_im)
c_im = -phi
c_re = do('imag', c_im)
c = do('exp', do('complex', c_re, c_im))
data = [[[[1, 0], [0, 0]],
[[0, a], [b, 0]]],
[[[0, b], [a, 0]],
[[0, 0], [0, c]]]]
return ops.asarray(data)
def apply_fsim(psi, theta, phi, i, j, parametrize=False, **gate_opts):
mtags = _merge_tags('FSIM', gate_opts)
if parametrize:
G = ops.PArray(fsim_param_gen, (theta, phi))
else:
G = qu.fsim(theta, phi)
psi.gate_(G, (int(i), int(j)), tags=mtags, **gate_opts)

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
Copy link
Author

yuxuanzhang1995 commented Mar 28, 2022 via email

@ghost
Copy link

ghost commented May 7, 2022

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
Copy link
Owner

jcmgray commented May 9, 2022

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
Copy link
Owner

jcmgray commented Jul 6, 2022

As of 576edce, 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
Copy link
Author

yuxuanzhang1995 commented Oct 11, 2022 via email

@jcmgray
Copy link
Owner

jcmgray commented Oct 11, 2022

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

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

No branches or pull requests

2 participants