Expressions, funcions i comparacions

Expressions

Les variables es poden combinar algebraicament amb els operadors habituals de Python (+, -, *, /, **) per construir una Expression simbòlica. Cada fulla (una variable, un paràmetre o una constant numèrica) i cada node operador (Add, Mul, Pow) és en si mateix una Expression, de manera que les expressions es componen lliurement. Per exemple:

from qilisdk.core.variables import BinaryVariable, Bitwise, Domain, SpinVariable, Variable
x = Variable("x", domain=Domain.REAL, bounds=(1, 2), encoding=Bitwise, precision=1e-1)
s = SpinVariable("s")
b = BinaryVariable("b")

e1 = 2 * x + 3
print("e1:", e1)
e2 = 3 * x**2 + 2 * x + 4
print("e2:", e2)
e3 = 2 * x + b - 1
print("e3:", e3)
e4 = e1 - e2
print("e4:", e4)

Sortida:

e1: 3 + 2 * x
e2: 4 + 2 * x + 3 * x**2
e3: -1 + b + 2 * x
e4: 3 - (4 + 2 * x + 3 * x**2) + 2 * x

En el moment de la construcció canonitzem l’expressió (aplanant sumes i productes imbricats, combinant termes semblants, ordenant els operands, etc.), de manera que x + y + 1 és igual a y + 1 + x. Els productes no es distribueixen sobre les sumes, així que e4 conserva la subexpressió factoritzada - (4 + 2 * x + 3 * x**2). Utilitzeu expand() per distribuir:

print(e4.expand())          # distribute the product over the sum

Sortida:

-1 - 3 * x**2

Les expressions es poden avaluar proporcionant valors per a les variables implicades mitjançant evaluate():

e3.evaluate({
    x: 1.5,
    b: 0
})

Sortida:

2.0

Avís

Per avaluar una expressió, a totes les variables participants se’ls han d’assignar valors vàlids dins dels seus dominis i límits respectius.

Inspeccionar i derivar expressions

Una Expression exposa una sèrie de funcions auxiliars. Podeu llistar les fulles amb nom de les quals depèn, aïllar únicament les fulles Parameter lliures, llegir el seu degree polinòmic o calcular una derivada simbòlica amb derivative():

from qilisdk.core.variables import Parameter, Variable, Domain

a = Parameter("a", value=2.0)
y = Variable("y", domain=Domain.REAL, bounds=(0, 5))

expr = a * y**2 + 3 * y

print(expr.variables())          # named leaves, sorted by label
print(expr.free_parameters())    # only the Parameter leaves
print(expr.degree)               # highest polynomial degree (a and y both count)
print(expr.derivative(y))              # symbolic d/dy

Sortida:

[a, y]
{a}
3
3 + 2 * a * y

Funcions matemàtiques

Les operacions no polinòmiques es representen amb Function, la base abstracta de les funcions matemàtiques unàries. Cadascuna de les seves subclasses concretes (llistades més avall) embolcalla un únic operand Expression (un Parameter, qualsevol altra variable o una expressió composta) i ajorna l’avaluació numèrica fins que es proporcionen valors.

from qilisdk.core.expression import Cos, Sin
from qilisdk.core.variables import Parameter

theta = Parameter("theta", 0.5)
expr = Sin(theta) + Cos(2 * theta)

print(expr)                # Cos(2 * theta) + Sin(theta)
print(expr.evaluate({}))   # uses theta.value automatically

# You can also supply a different value at evaluation time:
print(expr.evaluate({theta: 1.0}))

Sortida:

Cos(2 * theta) + Sin(theta)
1.0197278444723428
0.4253241482607541

Com que cada funció és un node Expression normal, participa en la mateixa àlgebra: es pot sumar o multiplicar amb altres expressions, derivar simbòlicament (la regla de la cadena s’aplica automàticament) i avaluar. Embolcallar una constant numèrica es plega immediatament a una Constant:

from qilisdk.core.expression import Cos, Exp, Sin
from qilisdk.core.variables import Parameter

theta = Parameter("theta", 0.5)

print(Sin(theta).derivative(theta))   # d/dtheta Sin(theta) == Cos(theta)
print(Exp(theta).derivative(theta))   # d/dtheta Exp(theta) == Exp(theta)
print(Cos(0))                   # folds to a numeric constant

Sortida:

Cos(theta)
Exp(theta)
1.0

Aquestes funcions es componen de manera natural amb la resta de l’arbre d’expressions, de manera que les podeu incloure en restriccions, objectius o coeficients de schedules i es regeixen per les mateixes regles d’avaluació i codificació que qualsevol altra expressió simbòlica.

Els nodes de funció disponibles són:

  • Sin per al sinus

  • Cos per al cosinus

  • Tan per a la tangent

  • Exp per a l’exponencial

  • Log per al logaritme

  • Sqrt per a l’arrel quadrada

  • Abs per al valor absolut

Abs és l’única funció sense derivada: no és derivable a zero i no existeix cap node sign amb què escriure la seva derivada, de manera que derivative() llança un error sobre ella.

Per a les potències, utilitzeu l’operador **, que construeix un node Pow i admet un exponent fraccionari o simbòlic. Inv() és una abreviatura de x ** -1, així que Inv(x), 1 / x i x ** -1 són totes la mateixa expressió:

from qilisdk.core.expression import Inv
from qilisdk.core.variables import Parameter

x, y = Parameter("x", 4.0), Parameter("y", 0.5)

print(x**y)                       # symbolic exponent
print((x**y).evaluate({}))
print(Inv(x) == 1 / x == x**-1)

Sortida:

x**y
2.0
True

Per escriure la vostra pròpia funció, creeu una subclasse de Function amb un NAME, un nucli numèric i una derivada. Tota la resta (canonització, igualtat, derivative, expand, substitute, serialització) la proporciona la classe base.

Comparacions

Una Comparison relaciona dues expressions i és allò a partir del qual es construeix una Constraint. No és una Expression en si mateixa. Utilitzeu els operadors següents per construir-ne una:

Operació de comparació

Mètode QiliSDK

Àlies

Igualtat

Equal(lhs, rhs)

EQ(lhs, rhs)

Diferent de

NotEqual(lhs, rhs)

NEQ(lhs, rhs)

Menor que

LessThan(lhs, rhs)

LT(lhs, rhs)

Menor o igual que

LessThanOrEqual(lhs, rhs)

LEQ(lhs, rhs)

Major que

GreaterThan(lhs, rhs)

GT(lhs, rhs)

Major o igual que

GreaterThanOrEqual(lhs, rhs)

GEQ(lhs, rhs)

Nota: lhs i rhs fan referència a les expressions del costat esquerre i del costat dret, respectivament.

Exemple:

from qilisdk.core.comparison import LT
from qilisdk.core.variables import BinaryVariable
x = BinaryVariable("x")
print(LT(2 * x - 1, 1))

Sortida:

2 * x < 2

Quan es crea un terme de comparació, les constants es mouen automàticament al costat dret i els termes amb variables al costat esquerre.