<jupyter_start><jupyter_text>Advanced VQE usageThere exist several parameters for configuring and using more advanced [VQE](https://qiskit.org/documentation/stubs/qiskit.aqua.algorithms.VQE.html) capabilities. This tutorial will cover the parameters such as `initial_point`, `expectation` and `gradient`.It will also cover advanced simulator use such as using Aer with the Matrix Product State method.<jupyter_code>from qiskit import BasicAer
from qiskit.aqua.operators import X, Z, I
from qiskit.aqua import QuantumInstance, aqua_globals
from qiskit.aqua.algorithms import VQE
from qiskit.aqua.components.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal<jupyter_output><empty_output><jupyter_text>Here we will use the same operator as used in the other VQE algorithms tutorials.<jupyter_code>H2_op = (-1.052373245772859 * I ^ I) + \
        (0.39793742484318045 * I ^ Z) + \
        (-0.39793742484318045 * Z ^ I) + \
        (-0.01128010425623538 * Z ^ Z) + \
        (0.18093119978423156 * X ^ X)<jupyter_output><empty_output><jupyter_text>Initial pointThe `initial_point` parameter allows the optimization to begin at the given point, where the point is a list of parameters that will configure the variational form. By default the initial point is `None` which means that VQE will choose one. The choice in in this case is if the supplied variational form has a preferred point, based on the initial state provided to it, then this will be chosen, otherwise a random initial point that fits with any bounds the variational has will be chosen. If an initial point is supplied it will take priority though and be used - note though it must match in length to the number of parameters in the variational form circuit.Why to use a initial point? One reason would be if you have guess a reasonable starting point for the problem or perhaps know have information from a prior experiment.To demonstrate the use let's first simply repeat the first working example from the [algorithms introduction](01_algorithms_introduction.ipynbA-complete-working-example) tutorial to get a solution's optimal point.<jupyter_code>from qiskit.aqua import aqua_globals
seed = 50
aqua_globals.random_seed = seed
qi = QuantumInstance(BasicAer.get_backend('statevector_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(result)<jupyter_output>{   'cost_function_evals': 72,
    'eigenstate': array([-9.55448660e-05+2.12037105e-17j,  9.93766273e-01+2.25293943e-16j,
       -1.11483565e-01+1.52657541e-16j, -1.77521351e-05+3.71607315e-17j]),
    'eigenvalue': (-1.857275017559769+0j),
    'optimal_parameters': {   Parameter(θ[0]): 4.296520551468743,
                              Parameter(θ[1]): 4.426962086704216,
                              Parameter(θ[2]): 0.5470753710293924,
                              Parameter(θ[3]): 6.09294789784282,
                              Parameter(θ[4]): -2.598325857134344,
                              Parameter(θ[5]): 1.5683261371389359,
                              Parameter(θ[6]): -4.717618235040379,
                              Parameter(θ[7]): 0.3602072316165878},
    'optimal_point': array([ 4.29652055,  4.42696209,  0.54707537,  6.0929479 , -2.59832586,
        1.56832614, -4.71761824,  0.36020723]),
    'optimal_value': -1.857275017559769,
    'optimizer_evals': 72,
    'optimizer_tim[...]<jupyter_text>Now we can take the `optimal_point` from the above result and use it as the `initial_point` here.<jupyter_code>initial_pt = result.optimal_point

aqua_globals.random_seed = seed
qi = QuantumInstance(BasicAer.get_backend('statevector_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, initial_point=initial_pt, quantum_instance=qi)
result1 = vqe.run()

pp.pprint(result1)<jupyter_output>{   'cost_function_evals': 10,
    'eigenstate': array([-9.55448660e-05+2.12037105e-17j,  9.93766273e-01+2.25293943e-16j,
       -1.11483565e-01+1.52657541e-16j, -1.77521351e-05+3.71607315e-17j]),
    'eigenvalue': (-1.857275017559769+0j),
    'optimal_parameters': {   Parameter(θ[1]): 4.426962086704216,
                              Parameter(θ[0]): 4.296520551468743,
                              Parameter(θ[4]): -2.598325857134344,
                              Parameter(θ[6]): -4.717618235040379,
                              Parameter(θ[3]): 6.09294789784282,
                              Parameter(θ[2]): 0.5470753710293924,
                              Parameter(θ[5]): 1.5683261371389359,
                              Parameter(θ[7]): 0.3602072316165878},
    'optimal_point': array([ 4.29652055,  4.42696209,  0.54707537,  6.0929479 , -2.59832586,
        1.56832614, -4.71761824,  0.36020723]),
    'optimal_value': -1.857275017559769,
    'optimizer_evals': 10,
    'optimizer_tim[...]<jupyter_text>Here we we see that result was arrived at much more quickly where `optimizer_evals` is 10 versus 72 when it started from a random value when the initial point was not supplied (default of None).Where this becomes useful for examples where we the solution to one problem can be used to for a guess for the solution to a very close similar problem. Chemistry is very good example where we change the inter-atomic distance(s) of molecule to plot a dissociation profile. When the distance changes are small we expect the solution to still be nearby the prior one. One technique is to simply use the optimal point from one solution as the starting point for the next step. Now more complex techniques are possible that do some extrapolation to compute an initial based on prior solution(s) rather than directly use the prior solution. The Qiskit Chemistry [sampling_potential_energy_surfaces](../chemistry/05_Sampling_potential_energy_surfaces.ipynbExtrapolation) tutorial shows such bootstrapping and extrapolation.  ExpectationThe energy of the Hamiltonian operator that VQE is working on is the expectation value when evaluated with the parameterized variational form. To compute the expectation value VQE uses an instance of an [expectation](https://qiskit.org/documentation/apidoc/qiskit.aqua.operators.expectations.html) object. Such an instance may be supplied via the `expectation` parameter, or in the default case, where it has a value of `None`, VQE will use the [ExpectationFactory](https://qiskit.org/documentation/stubs/qiskit.aqua.operators.expectations.ExpectationFactory.html) to create itself a suitable instance based on the supplied backend.For most cases letting VQE create a suitable instance is sufficient. However the Qiskit Aer qasm_simulator supports a snapshot instruction that can be used in conjunction with the operator expectation computation. If used then the outcome is ideal, i.e. like the statevector simulator, and has no shot noise. Since people normally choose the qasm_simulator to have shot noise (sampling noise), and be more like a real-device outcome, VQE has an `include_custom` flag that is passed on to the ExpectationFactory. When using Aer qasm simulator, and this is set `True`, the factory will return `AerPauliExpectation`  which uses the snapshot instruction, when `False`, default, then the regular `PauliExpectation` is returned.The following example shows `include_custom=True` where the outcome matches the statevector simulator. In fact it can be better/faster to do this than use the statevector_simulator directly. This is because in the latter case when the Hamiltonian is a sum of Paulis it must be converted to matrix form, and this is avoided when when using the snapshot instruction done when include_custom is True.<jupyter_code>from qiskit import Aer

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi, include_custom=True)
result = vqe.run()

pp.pprint(result)<jupyter_output>{   'cost_function_evals': 72,
    'eigenstate': {'01': 1008, '10': 16},
    'eigenvalue': (-1.8572750175597519+0j),
    'optimal_parameters': {   Parameter(θ[0]): 4.296520463599476,
                              Parameter(θ[1]): 4.426962139199476,
                              Parameter(θ[2]): 0.5470754235069875,
                              Parameter(θ[3]): 6.092947836794945,
                              Parameter(θ[4]): -2.5983258956331645,
                              Parameter(θ[5]): 1.568326000491598,
                              Parameter(θ[6]): -4.717618128585369,
                              Parameter(θ[7]): 0.3602072910298268},
    'optimal_point': array([ 4.29652046,  4.42696214,  0.54707542,  6.09294784, -2.5983259 ,
        1.568326  , -4.71761813,  0.36020729]),
    'optimal_value': -1.8572750175597519,
    'optimizer_evals': 72,
    'optimizer_time': 1.2052154541015625}<jupyter_text>In case you have doubts here is the qasm_simulator again but include_custom has been left to default to False. The optimization ended abruptly, presumably due to the shot noise confusing the SLSQP optimizer. The optimal value can be seen to be wrong too, i.e. -1.098 versus the correct -1.857.<jupyter_code>aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

pp.pprint(result)<jupyter_output>{   'cost_function_evals': 10,
    'eigenstate': {'00': 620, '01': 244, '10': 159, '11': 1},
    'eigenvalue': (-1.0987888676631705+0j),
    'optimal_parameters': {   Parameter(θ[5]): 1.8462931831829383,
                              Parameter(θ[6]): -5.466043598406607,
                              Parameter(θ[7]): 0.6984088030463615,
                              Parameter(θ[2]): 0.6019852007557844,
                              Parameter(θ[1]): 4.19301252102391,
                              Parameter(θ[0]): 3.611860069224077,
                              Parameter(θ[4]): -3.3070470445355764,
                              Parameter(θ[3]): 5.949536809130025},
    'optimal_point': array([ 3.61186007,  4.19301252,  0.6019852 ,  5.94953681, -3.30704704,
        1.84629318, -5.4660436 ,  0.6984088 ]),
    'optimal_value': -1.0987888676631705,
    'optimizer_evals': 10,
    'optimizer_time': 0.5309410095214844}<jupyter_text>Changing the optimizer to SPSA, which is designed to work in noisy environments, gets us a better result. Though the noise has affected the outcome so it's not as accurate.<jupyter_code>from qiskit.aqua.components.optimizers import SPSA

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SPSA(maxiter=100)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

pp.pprint(result)<jupyter_output>{   'cost_function_evals': 241,
    'eigenstate': {'01': 1007, '10': 17},
    'eigenvalue': (-1.8623464125433034+0j),
    'optimal_parameters': {   Parameter(θ[3]): 7.149874669811867,
                              Parameter(θ[7]): -1.8648388048829714,
                              Parameter(θ[2]): 2.146860065695897,
                              Parameter(θ[1]): 2.0047037904408738,
                              Parameter(θ[5]): 0.026059065222908795,
                              Parameter(θ[6]): -4.4426207121597745,
                              Parameter(θ[4]): -4.6685058886658455,
                              Parameter(θ[0]): 4.731406884288576},
    'optimal_point': array([ 4.73140688,  2.00470379,  2.14686007,  7.14987467, -4.66850589,
        0.02605907, -4.44262071, -1.8648388 ]),
    'optimal_value': -1.8623464125433034,
    'optimizer_time': 11.047632932662964}<jupyter_text>As mentioned above, an expectation object can be explicitly given (so the internal `ExpectationFactory` and include_custom are never used/needed. Below we create an `AerPauliExpectation` and pass this to VQE. We can see the result matches that above where we set include_custom to True and let VQE create its own expectation object.<jupyter_code>from qiskit.aqua.operators import AerPauliExpectation

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi,
          expectation=AerPauliExpectation())
result = vqe.run()

pp.pprint(result)<jupyter_output>{   'cost_function_evals': 72,
    'eigenstate': {'01': 1008, '10': 16},
    'eigenvalue': (-1.8572750175597519+0j),
    'optimal_parameters': {   Parameter(θ[5]): 1.568326000491598,
                              Parameter(θ[6]): -4.717618128585369,
                              Parameter(θ[4]): -2.5983258956331645,
                              Parameter(θ[2]): 0.5470754235069875,
                              Parameter(θ[3]): 6.092947836794945,
                              Parameter(θ[7]): 0.3602072910298268,
                              Parameter(θ[0]): 4.296520463599476,
                              Parameter(θ[1]): 4.426962139199476},
    'optimal_point': array([ 4.29652046,  4.42696214,  0.54707542,  6.09294784, -2.5983259 ,
        1.568326  , -4.71761813,  0.36020729]),
    'optimal_value': -1.8572750175597519,
    'optimizer_evals': 72,
    'optimizer_time': 1.3454556465148926}<jupyter_text>By default, the `PauliExpectation` object, that would have be chosen when include_custom is False (or when using BasicAer qasm_simultor, or a real device) groups Paulis into commuting sets. This is efficient as it runs less circuits to compute the expectation. However, if for some reason you wanted to run a circuit for each Pauli then then grouping can be turned off when constructing the PauliExpectation. You need to explicitly pass in such an expectation instance to VQE to have it work this way though as shown below.<jupyter_code>from qiskit.aqua.operators import PauliExpectation

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SPSA(maxiter=100)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi,
          expectation=PauliExpectation(group_paulis=False))
result = vqe.run()

pp.pprint(result)<jupyter_output>{   'cost_function_evals': 241,
    'eigenstate': {'01': 1007, '10': 17},
    'eigenvalue': (-1.8667499370593512+0j),
    'optimal_parameters': {   Parameter(θ[1]): 2.1216349904032947,
                              Parameter(θ[7]): -1.9698662442728732,
                              Parameter(θ[5]): 0.2634941452871489,
                              Parameter(θ[6]): -4.360567678129973,
                              Parameter(θ[0]): 4.718047005792739,
                              Parameter(θ[4]): -4.733789920734712,
                              Parameter(θ[2]): 2.1876557567510497,
                              Parameter(θ[3]): 7.317481602611872},
    'optimal_point': array([ 4.71804701,  2.12163499,  2.18765576,  7.3174816 , -4.73378992,
        0.26349415, -4.36056768, -1.96986624]),
    'optimal_value': -1.8667499370593512,
    'optimizer_time': 20.964618682861328}<jupyter_text>GradientOptimizers that use a gradient-based technique can be supplied with a user defined gradient that will be used instead of their default gradient computation which is usually done by simple finite difference. Gradients are passed indirectly via to the optimizer via its `gradient` parameter.As the use of a user supplied `gradient` was shown in the [Monitoring VQE Convergence](02_vqe_convergence.ipynbUsing-Gradient-framework) tutorial I will simply refer you there. Also the [Gradients framework](../operators/02_gradients_framework.ipynb) tutorial has much more about the gradients themselves.  Quantum Instance and advanced simulationWhile you may be familar with passing a QuantumInstancen created from a `statevector_simulator` a `qasm_simulator` or   real device backend, it is possible to use the advanced simulation modes of Aer too when applicable. For instance we can easily use the Aer [Matrix Product State](../simulators/7_matrix_product_state_method.ipynb) method, that has the potential to scale to larger numbers of qubits.<jupyter_code>aqua_globals.random_seed = seed

from qiskit.providers.aer import QasmSimulator
quantum_instance = QuantumInstance(QasmSimulator(method='matrix_product_state'), shots=1)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi, include_custom=True)
result = vqe.run()

pp.pprint(result)
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09737081720919645, 'fraction_numerical': 0.12559754154336444, 'mean_word_length': 3.5584954604409855, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 34, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '201800', 'license': 'Apache-2.0', 'n_tokens_mistral': 6983, 'n_tokens_neox': 5578, 'n_words': 1499, 'path': 'tutorials/algorithms/04_vqe_advanced.ipynb', 'repo_name': 'chriseclectic/qiskit-tutorial', 'size': '17572'}