Skip to content

Add explicit adjoint for qubitization walk operator #937

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

Merged
merged 3 commits into from
May 10, 2024

Conversation

tanujkhattar
Copy link
Collaborator

Fixes #936

Note that symbolic case reported in #935 (comment) but that is now because of a niche sympy error. The core issue is that big_O() notation does not play well with "add up summations of individual terms" logic implemented in the T-complexity protocol.

See the details below for the error raised when testing t-complexity for symbolic hamiltonian simulation via gqsp bloq

>       _ = symbolic_hamsim_by_gqsp.gqsp.t_complexity()

qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp_test.py:103:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
qualtran/_infra/bloq.py:427: in t_complexity
    return t_complexity(self)
qualtran/cirq_interop/t_complexity_protocol.py:246: in t_complexity
    ret = _t_complexity_for_gate_or_op(stc)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/cachetools/__init__.py:675: in wrapper
    v = func(*args, **kwargs)
qualtran/cirq_interop/t_complexity_protocol.py:230: in _t_complexity_for_gate_or_op
    return _t_complexity_from_strategies(gate_or_op, strategies)
qualtran/cirq_interop/t_complexity_protocol.py:209: in _t_complexity_from_strategies
    ret = strategy(stc)
qualtran/cirq_interop/t_complexity_protocol.py:171: in _from_bloq_build_call_graph
    ret += n * r
qualtran/cirq_interop/t_complexity_protocol.py:57: in __add__
    self.t + other.t, self.clifford + other.clifford, self.rotations + other.rotations
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/decorators.py:236: in _func
    return func(self, other)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/decorators.py:106: in binary_op_wrapper
    return func(self, other)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/expr.py:198: in __add__
    return Add(self, other)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/operations.py:98: in __new__
    c_part, nc_part, order_symbols = cls.flatten(args)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/add.py:367: in flatten
    if o.contains(t):
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/series/order.py:452: in contains
    obj = self.func(expr, *self.args[1:])
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/series/order.py:203: in __new__
    expr = expr.subs(s)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1040: in subs
    rv = rv._subs(old, new, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1154: in _subs
    rv = fallback(self, old, new)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1126: in fallback
    arg = arg._subs(old, new, **hints)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1154: in _subs
    rv = fallback(self, old, new)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1126: in fallback
    arg = arg._subs(old, new, **hints)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/basic.py:1152: in _subs
    rv = self._eval_subs(old, new)
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/series/order.py:499: in _eval_subs
    return Order(newexpr, *zip(newvars, newpt))
../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/core/cache.py:72: in wrapper
    retval = cfunc(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'sympy.series.order.Order'>, expr = t + log(_Dummy_434)/log(-log(_Dummy_434)), args = [(_Dummy_434, 0), (t, oo)], kwargs = {}, variables = [_Dummy_434, t], a = (t, oo), v = t, p = oo

    @cacheit
    def __new__(cls, expr, *args, **kwargs):
        expr = sympify(expr)

        if not args:
            if expr.is_Order:
                variables = expr.variables
                point = expr.point
            else:
                variables = list(expr.free_symbols)
                point = [S.Zero]*len(variables)
        else:
            args = list(args if is_sequence(args) else [args])
            variables, point = [], []
            if is_sequence(args[0]):
                for a in args:
                    v, p = list(map(sympify, a))
                    variables.append(v)
                    point.append(p)
            else:
                variables = list(map(sympify, args))
                point = [S.Zero]*len(variables)

        if not all(v.is_symbol for v in variables):
            raise TypeError('Variables are not symbols, got %s' % variables)

        if len(list(uniq(variables))) != len(variables):
            raise ValueError('Variables are supposed to be unique symbols, got %s' % variables)

        if expr.is_Order:
            expr_vp = dict(expr.args[1:])
            new_vp = dict(expr_vp)
            vp = dict(zip(variables, point))
            for v, p in vp.items():
                if v in new_vp.keys():
                    if p != new_vp[v]:
                        raise NotImplementedError(
                            "Mixing Order at different points is not supported.")
                else:
                    new_vp[v] = p
            if set(expr_vp.keys()) == set(new_vp.keys()):
                return expr
            else:
                variables = list(new_vp.keys())
                point = [new_vp[v] for v in variables]

        if expr is S.NaN:
            return S.NaN

        if any(x in p.free_symbols for x in variables for p in point):
            raise ValueError('Got %s as a point.' % point)

        if variables:
            if any(p != point[0] for p in point):
>               raise NotImplementedError(
                    "Multivariable orders at different points are not supported.")
E               NotImplementedError: Multivariable orders at different points are not supported.

../../opt/anaconda3/envs/qualtran2/lib/python3.11/site-packages/sympy/series/order.py:184: NotImplementedError

This case can be fixed in a followup PR. cc @anurudhp

@tanujkhattar tanujkhattar enabled auto-merge (squash) May 10, 2024 18:07
@tanujkhattar tanujkhattar merged commit 1975b7d into quantumlib:main May 10, 2024
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.

walk_op.adjoint().controlled().t_complexity() fails but walk_op.controlled().adjoint().t_complexity() passes
2 participants