Parameters

As discussed in previous sections, ansatzes are typically defined by a set of parameters. These parameters are handled in InQuanto by means of the two classes: SymbolSet and SymbolDict. Both represent symbolic parameters – the difference between them is that SymbolDict associates each parameter with a specific value, whereas SymbolSet does not. In essence, both are wrappers over a Python dict data structure (with the SymbolSet values set to None and non-accessible), ensuring consistency in the order in which symbols are added. The keys of a SymbolSet or SymbolDict are sympy.Symbol objects, and thus may be manipulated or created using the SymPy library if required. Additional convenience methods for SymbolSet and SymbolDict are also included. In general, when an ansatz is being constructed, its state_symbols member variable represents a SymbolSet object - just a set of symbolic parameters, without any values assigned. One can also retrieve a SymbolSet object from the symbolic operator objects using the free_symbols() method:

from inquanto.operators import FermionOperatorList
operator = FermionOperatorList.from_string("d0 [(1.0, F2^ F0 F3^ F1)], d1 [(1.0, F4^ F0 F5^ F1)]")
symbols = operator.free_symbols()
print(symbols)
{d0, d1}

and substitute free symbols with the numeric values using the .subs() method:

from sympy import Symbol
operator.subs({Symbol("d0"): 0.9, Symbol("d1"): 0.1})
print(operator)
d0        [(1.0, F2^ F0  F3^ F1 )],
d1        [(1.0, F4^ F0  F5^ F1 )]

When initiating an Algorithm object, it is common to pass initial values for ansatz parameters. Here, convenience methods such as construct_from_array(), construct_zeros() and construct_random() can be used to convert a SymbolSet object to a SymbolDict object, with each symbol being mapped to its value. The order of symbols is maintained in this conversion. For example, with the custom circuit constructed above:

from inquanto.ansatzes import RealRestrictedBasisRotationAnsatz
my_ansatz = RealRestrictedBasisRotationAnsatz(2)
random_param = my_ansatz.state_symbols.construct_random()
print(random_param)
{phi_0: 0.9417154046806644, phi_1: -1.3965781047011498, theta_1_0: -0.6797144480784211}

If necessary, a SymbolDict object can be manipulated in the same way as an ordinary Python dict, i.e. by updating, adding or removing elements:

from inquanto.core import SymbolDict
sd = SymbolDict(a=1, b=2)
sd["b"] = 3
sd["c"] = 2
sd.discard("a")
print(sd)
{b: 3, c: 2}