def match_phase_gadgets(g):
    """Determines which phase gadgets act on the same vertices, so that they can be fused together.
    
    :param g: An instance of a ZX-graph.
    :rtype: List of 5-tuples ``(axel,leaf, total combined phase, other axels with same targets, other leafs)``.
    """
    phases = g.phases()
    parities = dict()
    gadgets = dict()
    for v in g.vertices():
        if phases[v] != 0 and phases[v].denominator > 2 and len(list(g.
            neighbours(v))) == 1:
            n = list(g.neighbours(v))[0]
            if phases[n] not in (0, 1):
                continue
            if n in gadgets:
                continue
            if n in g.inputs or n in g.outputs:
                continue
            gadgets[n] = v
            par = frozenset(set(g.neighbours(n)).difference({v}))
            if par in parities:
                parities[par].append(n)
            else:
                parities[par] = [n]
    m = []
    for par, gad in parities.items():
        if len(gad) == 1:
            n = gad[0]
            v = gadgets[n]
            if phases[n] != 0:
                g.scalar.add_phase(phases[v])
                g.phase_negate(v)
                m.append((v, n, -phases[v], [], []))
        else:
            totphase = sum((1 if phases[n] == 0 else -1) * phases[gadgets[n
                ]] for n in gad) % 2
            for n in gad:
                if phases[n] != 0:
                    g.scalar.add_phase(phases[gadgets[n]])
                    g.phase_negate(gadgets[n])
            g.scalar.add_power(-((len(par) - 1) * (len(gad) - 1)))
            n = gad.pop()
            v = gadgets[n]
            m.append((v, n, totphase, gad, [gadgets[n] for n in gad]))
    return m
