Source code for normal_forms.lie_operator
import numpy as np
import sympy
import combinatorics
import bases
import copy
[docs]class lie_operator(object):
"""Lie operator of a vector field.
In this implementation, the Lie bracket of vector fields :math:`f,g:\\mathbb{R}^n\\rightarrow\\mathbb{R}^n` is defined as :math:`[f,g]=f'(x)g(x)-g'(x)f(x)`. An object of this class represents the Lie bracket with a particular vector field :math:`g`, denoted :math:`L_g(\\cdot)=[g,\\cdot]`.
Parameters
----------
g : ``sympy.Matrix(m,1)``
symbolic representation of degree ``deg`` homogenous polynomial vector field in variables ``var``
var : list of ``n sympy.symbol`` objects
arguments ``x_0``, ``x_``, ..., ``x_{n-1}`` of polynomial components of ``g``
deg : int, optional
degree of ``g``. If not supplied, it is guessed from the terms in ``g``.
pb : ``normal_forms.bases.poly_basis``, optional
polynomial basis, see ``normal_forms.bases``
vb : ``normal_forms.bases.vf_basis``, opetional
polynomial vector field basis, see ``normal_forms.bases``
Attributes
----------
dg : ``sympy.Matrix(m,n)``
coefficients of derivative of ``g`` with respect to basis ``pb``
matrix : dict of ``numpy.array`` objects
matrix representations of Lie operator acting on homogenous polynomial vector fields
"""
def __init__(self, g, var, deg=None, pb=None, vb=None):
m = len(g)
n = len(var)
self.g = g
# try to guess degree of g if not supplied
if deg is None and g.norm() != 0:
idx = 0
while g[idx] == 0:
idx += 1
deg = sympy.poly(g[idx]).total_degree()
self.deg = deg
self.var = var
self.m = m
self.n = n
# construct bases if not supplied
if pb is None:
pb = bases.poly_basis(var)
if vb is None:
vb = bases.vf_basis(pb, m)
self.pb = pb
self.vb = vb
# derivative of g with respect to basis pb
dg = sympy.zeros(m, n)
for i in range(n):
dg[:, i] = sympy.diff(g, var[i])
self.dg = dg
# dict of matrix representations of Lie operator
self.matrix = {}
[docs] def add_matrix(self, deg):
"""Add to dict ``matrix`` the matrix representation of Lie operator acting on homogenous degree ``deg`` :math:`m`-dimensional polynomial vector field.
Parameters
----------
deg : int
degree of vector field argument to Lie operator :math:`L_g`
"""
m = self.m
n = self.n
pb = self.pb
vb = self.vb
var = self.var
g = self.g
dg = self.dg
# number of vf basis elements of degree deg
n_vf = len(vb[deg])
# derivatives of vb with respect to pb
dvb = [sympy.zeros(m, n) for _ in range(n_vf)]
for i in range(n_vf):
for j in range(n):
dvb[i][:, j] = sympy.diff(vb[deg][i], var[j])
# symbolic Lie operator action on vb
bracket = [
sympy.expand(dvb[i] * g - dg * vb[deg][i]) for i in range(n_vf)
]
# number of coefficients to specify a vector field in Lie operator codomain
n_terms = len(pb[self.deg + deg - 1])
# store matrix representation from coefficients of bracket
mat = np.empty([m * n_terms, n_vf])
for j in range(n_vf):
for coord in range(m):
for i in range(n_terms):
mat[coord * n_terms + i, j] = bracket[j][coord].coeff(
pb[self.deg + deg - 1][i])
self.matrix[deg] = mat
def __call__(self, f):
"""Apply Lie operator to a vector field.
Parameters
----------
f : ``sympy.Matrix(m,1)``
symbolic representation of homogenous polynomial vector field
Returns
-------
``sympy.Matrix(m,1)``
symbolic representation of Lie operator of vector field
"""
m = self.m
pb = self.pb
# Return zero if argument is zero, otherwise guess degree of argument
if f.norm() == 0:
return sympy.zeros(m, 1)
else:
idx = 0
while f[idx] == 0:
idx += 1
deg = sympy.poly(f[idx]).total_degree()
# if necessary matrix representation does not exist, construct it
if deg not in self.matrix.keys():
self.add_matrix(deg)
mat = self.matrix[deg]
# compute action of Lie operator as matrix-vector product
n_terms = mat.shape[1] / m
coeff = np.empty(m * n_terms)
for term in range(n_terms):
for coord in range(m):
coeff[coord * n_terms + term] = f[coord].coeff(pb[deg][term])
coeff = mat.dot(coeff)
# symbolic representation of result from coefficients
n_terms = mat.shape[0] / m
h = sympy.zeros(m, 1)
for coord in range(m):
h[coord] = pb[self.deg + deg - 1].dot(
coeff[coord * n_terms:(coord + 1) * n_terms]).expand()
return h
def __getitem__(self, deg):
"""Return matrix representation of operator acting on degree ``deg`` polynomial vector fields.
Parameters
----------
deg : int
degree of argument to Lie operator
Returns
-------
``numpy.array``
"""
# if necessary matrix representation does not exist, construct it
if deg not in self.matrix.keys():
self.add_matrix(deg)
return self.matrix[deg]