Closed HaoTy closed 8 months ago
TODOs:
E = -N**2/(2*F)
can be moved from 198 to 200. Make the change and see what tests fail.costs == None
, then use diagonal as costs).precomputed_costs
in get_qaoa_objective()
and remove precomputed_diagonal_hamiltonian
.To correct the point above, note that this fix is incorrect.
- Confirm that in LABS the normalization of
E = -N**2/(2*F)
can be moved from 198 to 200. Make the change and see what tests fail.
To understand why this works, note that qaoa_objective = <\psi | C |\psi>
. Since C = -(N**2) / (2 * y) - o
, so we can by linearity write <\psi | C |\psi> = <\psi| -(N**2) / (2 * y) | \psi> - o = (-(N**2) / 2) * <\psi| 1 / y | \psi> - o
However <\psi| 1 / y | \psi> = \sum_i \alpha_i**2 * (1/y_i) != 1 / (\sum_i \alpha_i**2 y_i)
. So for LABS, we must keep the distinction for backward compatibility.
The solution is as follows:
precomputed_diagonal_hamiltonian
the required one. We add the following error:
if precomputed_diagonal_hamiltonian is None and precomputed_costs is not None:
raise ValueError("precomputed_diagonal_hamiltonian should be passed instead of precomputed_costs")
This is to prevent logic around like 177-179 from breaking.
precomputed_diagonal_hamiltonian
.PO will also break as there's a scale difference between precomputed_diagonal_hamiltonian
and precomputed_costs
.
Since the primary goals for unifying the two are to reduce memory footprint and centralize the computation in fur with the user-specified backend, I think a reasonable solution is to pass in a function that takes precomputed_costs
and calculates precomputed_diagonal_hamiltonian
(or vice versa). This function should be able to deal with input from different backends (which should be quite straightforward), and an additional wrapper can be added in the mpi simulator to ensure this function is called exactly once for each gpu.
@HaoTy - Can we have call to discuss your idea?
As discussed with @rajgane07 on the call, we can stick to a simpler rescaling solution for portfolio optimization as it's only a linear transformation. Passing a conversion function as an argument for get_qaoa_objective creates significant engineering challenges for c
and mpi
simulators, and only improves the memory for the LABS use case. The other (including future) use cases will either only include a linear transformation or no transformation at all, avoiding this memory overhead. In this way, LABS is somewhat pathological.
For PO, we can change the code here as follows:
return get_qaoa_objective(
N=N,
p=p,
precomputed_diagonal_hamiltonian=po_problem["scale"] * precomputed_energies,
precomputed_optimal_bitstrings=precomputed_optimal_bitstrings,
parameterized_circuit=parameterized_circuit,
parameterization=parameterization,
objective=objective,
simulator=simulator,
mixer="xy",
initial_state=sv0,
n_trotters=T,
) / po_problem["scale"]
Thank you, @HaoTy, for you very valuable feedback which we very much appreciate! And also for pointing out the problem with the PO function.
As @HaoTy pointed out, the above solution does not handle the overlap correctly... The simplest fix is to add rescaling only when the objective is expectation. See rough idea for the code below. Perhaps there are more elegant solutions possible.
def scale_result(f):
def rescaled_f(*args):
if objective == "expectation":
return f(*args) / po_problem["scale"]
elif objective == "expectation and overlap":
res = f(*args)
return res[0] / po_problem["scale"], res[1]
else:
assert objective == "overlap"
return f(*args)
return rescaled_f
return scale_result(get_qaoa_objective(
N=N,
p=p,
precomputed_diagonal_hamiltonian=po_problem["scale"] * precomputed_energies,
precomputed_optimal_bitstrings=precomputed_optimal_bitstrings,
parameterized_circuit=parameterized_circuit,
parameterization=parameterization,
objective=objective,
simulator=simulator,
mixer="xy",
initial_state=sv0,
n_trotters=T,
))
@rsln-s @HaoTy Portfolio Optimization fails after removing precomputed_costs for qiskit simulator, "ValueError: precomputed_objectives or terms are required when using the expectation objective" We manage in Maxcut, by passing the terms if cuts is None. Similarly for portfolio is there a way to calculate terms? If yes, can you share the code or pseudo code to incorporate it.
Currently, there are two arguments related to precomputed energies in
get_qaoa_objective()
.precomputed_diagonal_hamiltonian
is passed into the simulator but not used for get-objective functions after the simulation, except whenprecomputed_costs
isNone
. However, judging from problem-specific get-objective functions, this exception is never the case, and even if so, it would produce incorrect results. Having two similar arguments leads to ambiguity and the duplication of the energy vector, whose size is exponential in the number of qubits.