def time_evolution( hamiltonian: QubitOperator, time: Union[float, sympy.Expr], method: str = "Trotter", trotter_order: int = 1, ) -> circuits.Circuit: """Create a circuit simulating evolution under given Hamiltonian. Args: hamiltonian: The Hamiltonian to be evolved under. time: Time duration of the evolution. method: Time evolution method. Currently the only option is 'Trotter'. trotter_order: order of Trotter evolution (1 by default). Returns: Circuit approximating evolution under `hamiltonian`. Circuit's unitary i approximately equal to exp(-i * time * hamiltonian). """ if method != "Trotter": raise ValueError(f"Currently the method {method} is not supported.") terms: Iterable = list(hamiltonian.get_operators()) return reduce( operator.add, (time_evolution_for_term(term, time / trotter_order) for _index_order in range(trotter_order) for term in terms), )
def time_evolution_derivatives( hamiltonian: QubitOperator, time: float, method: str = "Trotter", trotter_order: int = 1, ) -> Tuple[List[circuits.Circuit], List[float]]: """Generates derivative circuits for the time evolution operator defined in function time_evolution Args: hamiltonian: The Hamiltonian to be evolved under. It should contain numeric coefficients, symbolic expressions aren't supported. time: time duration of the evolution. method: time evolution method. Currently the only option is 'Trotter'. trotter_order: order of Trotter evolution Returns: A Circuit simulating time evolution. """ if method != "Trotter": raise ValueError(f"The method {method} is currently not supported.") single_trotter_derivatives = [] factors = [1.0, -1.0] output_factors = [] terms: Iterable = list(hamiltonian.get_operators()) for i, term_1 in enumerate(terms): for factor in factors: output = circuits.Circuit() try: if isinstance(term_1, QubitOperator): r = list(term_1.terms.values())[0] / trotter_order else: r = complex(term_1.coefficient).real / trotter_order except TypeError: raise ValueError("Term coefficients need to be numerical. " f"Offending term: {term_1}") output_factors.append(r * factor) shift = factor * (np.pi / (4.0 * r)) for j, term_2 in enumerate(terms): output += time_evolution_for_term( term_2, (time + shift) / trotter_order if i == j else time / trotter_order, ) single_trotter_derivatives.append(output) if trotter_order > 1: output_circuits = [] final_factors = [] repeated_circuit = time_evolution(hamiltonian, time, method="Trotter", trotter_order=1) for position in range(trotter_order): for factor, different_circuit in zip(output_factors, single_trotter_derivatives): output_circuits.append( _generate_circuit_sequence(repeated_circuit, different_circuit, trotter_order, position)) final_factors.append(factor) return output_circuits, final_factors else: return single_trotter_derivatives, output_factors