(target, origin, z)
return ops
Devise a plan (consisting of shift and un-shift operators) to be applied
    to the hypergeometric function ``target`` to yield ``origin``.
    Returns a list of operators.

    >>> from sympy.simplify.hyperexpand import devise_plan, Hyper_Function
    >>> from sympy.abc import z

    Nothing to do:

    >>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z)
    []
    >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z)
    []

    Very simple plans:

    >>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z)
    [<Increment upper 1.>]
    >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z)
    [<Increment lower index #0 of [], [1].>]

    Several buckets:

    >>> from sympy import S
    >>> devise_plan(Hyper_Function((1, S.Half), ()),
    ...             Hyper_Function((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE
    [<Decrement upper index #0 of [3/2, 1], [].>,
    <Decrement upper index #0 of [2, 3/2], [].>]

    A slightly more complicated plan:

    >>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z)
    [<Increment upper 2.>, <Decrement upper index #0 of [2, 2], [].>]

    Another more complicated plan: (note that the ap have to be shifted first!)

    >>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z)
    [<Decrement lower 3.>, <Decrement lower 4.>,
    <Decrement upper index #1 of [-1, 2], [4].>,
    <Decrement upper index #1 of [-1, 3], [4].>, <Increment upper -2.>]
Devise a plan (consisting of shift and un-shift operators) to be applied
    to the hypergeometric function ``target`` to yield ``origin``.
    Returns a list of operators.
Devise a plan ( consisting of shift and un - shift operators ) to be applied to the hypergeometric function target to yield origin . Returns a list of operators .
def devise_plan(target, origin, z):
    """
    Devise a plan (consisting of shift and un-shift operators) to be applied
    to the hypergeometric function ``target`` to yield ``origin``.
    Returns a list of operators.

    >>> from sympy.simplify.hyperexpand import devise_plan, Hyper_Function
    >>> from sympy.abc import z

    Nothing to do:

    >>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z)
    []
    >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z)
    []

    Very simple plans:

    >>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z)
    [<Increment upper 1.>]
    >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z)
    [<Increment lower index #0 of [], [1].>]

    Several buckets:

    >>> from sympy import S
    >>> devise_plan(Hyper_Function((1, S.Half), ()),
    ...             Hyper_Function((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE
    [<Decrement upper index #0 of [3/2, 1], [].>,
    <Decrement upper index #0 of [2, 3/2], [].>]

    A slightly more complicated plan:

    >>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z)
    [<Increment upper 2.>, <Decrement upper index #0 of [2, 2], [].>]

    Another more complicated plan: (note that the ap have to be shifted first!)

    >>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z)
    [<Decrement lower 3.>, <Decrement lower 4.>,
    <Decrement upper index #1 of [-1, 2], [4].>,
    <Decrement upper index #1 of [-1, 3], [4].>, <Increment upper -2.>]
    """
    abuckets, bbuckets, nabuckets, nbbuckets = [sift(params, _mod1) for
            params in (target.ap, target.bq, origin.ap, origin.bq)]

    if len(list(abuckets.keys())) != len(list(nabuckets.keys())) or \
            len(list(bbuckets.keys())) != len(list(nbbuckets.keys())):
        raise ValueError('%s not reachable from %s' % (target, origin))

    ops = []

    def do_shifts(fro, to, inc, dec):
        ops = []
        for i in xrange(len(fro)):
            if to[i] - fro[i] > 0:
                sh = inc
                ch = 1
            else:
                sh = dec
                ch = -1

            while to[i] != fro[i]:
                ops += [sh(fro, i)]
                fro[i] += ch

        return ops

    def do_shifts_a(nal, nbk, al, aother, bother):
        """ Shift us from (nal, nbk) to (al, nbk). """
        return do_shifts(nal, al, lambda p, i: ShiftA(p[i]),
                         lambda p, i: UnShiftA(p + aother, nbk + bother, i, z))

    def do_shifts_b(nal, nbk, bk, aother, bother):
        """ Shift us from (nal, nbk) to (nal, bk). """
        return do_shifts(nbk, bk,
                         lambda p, i: UnShiftB(nal + aother, p + bother, i, z),
                         lambda p, i: ShiftB(p[i]))

    for r in sorted(list(abuckets.keys()) + list(bbuckets.keys()), key=default_sort_key):
        al = ()
        nal = ()
        bk = ()
        nbk = ()
        if r in abuckets:
            al = abuckets[r]
            nal = nabuckets[r]
        if r in bbuckets:
            bk = bbuckets[r]
            nbk = nbbuckets[r]
        if len(al) != len(nal) or len(bk) != len(nbk):
            raise ValueError('%s not reachable from %s' % (target, origin))

        al, nal, bk, nbk = [sorted(list(w), key=default_sort_key)
            for w in [al, nal, bk, nbk]]

        def others(dic, key):
            l = []
            for k, value in dic.items():
                if k != key:
                    l += list(dic[k])
            return l
        aother = others(nabuckets, r)
        bother = others(nbbuckets, r)

        if len(al) == 0:
            # there can be no complications, just shift the bs as we please
            ops += do_shifts_b([], nbk, bk, aother, bother)
        elif len(bk) == 0:
            # there can be no complications, just shift the as as we please
            ops += do_shifts_a(nal, [], al, aother, bother)
        else:
            namax = nal[-1]
            amax = al[-1]

            if nbk[0] <= namax or bk[0] <= amax:
                raise ValueError('Non-suitable parameters.')

            if namax > amax:
                # we are going to shift down - first do the as, then the bs
                ops += do_shifts_a(nal, nbk, al, aother, bother)
                ops += do_shifts_b(al, nbk, bk, aother, bother)
            else:
                # we are going to shift up - first do the bs, then the as
                ops += do_shifts_b(nal, nbk, bk, aother, bother)
                ops += do_shifts_a(nal, bk, al, aother, bother)

        nabuckets[r] = al
        nbbuckets[r] = bk

    ops.reverse()
    return ops
def devise_plan ( target , origin , z ) : abuckets , bbuckets , nabuckets , nbbuckets = [ sift ( params , _mod1 ) for params in ( target . ap , target . bq , origin . ap , origin . bq ) ] if len ( list ( abuckets . keys ( ) ) ) != len ( list ( nabuckets . keys ( ) ) ) or len ( list ( bbuckets . keys ( ) ) ) != len ( list ( nbbuckets . keys ( ) ) ) : raise ValueError ( '%s not reachable from %s' % ( target , origin ) ) ops = [ ] def do_shifts ( fro , to , inc , dec ) : ops = [ ] for i in xrange ( len ( fro ) ) : if to [ i ] - fro [ i ] > 0 : sh = inc ch = 1 else : sh = dec ch = - 1 while to [ i ] != fro [ i ] : ops += [ sh ( fro , i ) ] fro [ i ] += ch return ops def do_shifts_a ( nal , nbk , al , aother , bother ) : """ Shift us from (nal, nbk) to (al, nbk). """ return do_shifts ( nal , al , lambda p , i : ShiftA ( p [ i ] ) , lambda p , i : UnShiftA ( p + aother , nbk + bother , i , z ) ) def do_shifts_b ( nal , nbk , bk , aother , bother ) : """ Shift us from (nal, nbk) to (nal, bk). """ return do_shifts ( nbk , bk , lambda p , i : UnShiftB ( nal + aother , p + bother , i , z ) , lambda p , i : ShiftB ( p [ i ] ) ) for r in sorted ( list ( abuckets . keys ( ) ) + list ( bbuckets . keys ( ) ) , key = default_sort_key ) : al = ( ) nal = ( ) bk = ( ) nbk = ( ) if r in abuckets : al = abuckets [ r ] nal = nabuckets [ r ] if r in bbuckets : bk = bbuckets [ r ] nbk = nbbuckets [ r ] if len ( al ) != len ( nal ) or len ( bk ) != len ( nbk ) : raise ValueError ( '%s not reachable from %s' % ( target , origin ) ) al , nal , bk , nbk = [ sorted ( list ( w ) , key = default_sort_key ) for w in [ al , nal , bk , nbk ] ] def others ( dic , key ) : l = [ ] for k , value in dic . items ( ) : if k != key : l += list ( dic [ k ] ) return l aother = others ( nabuckets , r ) bother = others ( nbbuckets , r ) if len ( al ) == 0 : # there can be no complications, just shift the bs as we please ops += do_shifts_b ( [ ] , nbk , bk , aother , bother ) elif len ( bk ) == 0 : # there can be no complications, just shift the as as we please ops += do_shifts_a ( nal , [ ] , al , aother , bother ) else : namax = nal [ - 1 ] amax = al [ - 1 ] if nbk [ 0 ] <= namax or bk [ 0 ] <= amax : raise ValueError ( 'Non-suitable parameters.' ) if namax > amax : # we are going to shift down - first do the as, then the bs ops += do_shifts_a ( nal , nbk , al , aother , bother ) ops += do_shifts_b ( al , nbk , bk , aother , bother ) else : # we are going to shift up - first do the bs, then the as ops += do_shifts_b ( nal , nbk , bk , aother , bother ) ops += do_shifts_a ( nal , bk , al , aother , bother ) nabuckets [ r ] = al nbbuckets [ r ] = bk ops . reverse ( ) return ops