A flexible way is to use the cirq.merge_operations
transformer which lets you pass in your own merge function that decides what operations to merge and how. For example:
def merge_func(op1: cirq.Operation, op2: cirq.Operation) -> Optional[cirq.Operation]:
if not isinstance(op1, cirq.GateOperation):
return None
if not isinstance(op2, cirq.GateOperation):
return None
if not isinstance(op1.gate, cirq.YPowGate):
return None
if not isinstance(op2.gate, cirq.YPowGate):
return None
return cirq.Y(*op1.qubits)**(op1.gate.exponent + op2.gate.exponent)
circuit = cirq.merge_operations(circuit, merge_func)