diff --git a/examples/test_cheb_lj_2p_xd.py b/examples/test_cheb_lj_2p_xd.py
index a39e07b7e8b3be6b6ac9fea3951533d17ea734e8..6deb8bf833dbe5b10419812d6adf6d7c5c1f2c16 100644
--- a/examples/test_cheb_lj_2p_xd.py
+++ b/examples/test_cheb_lj_2p_xd.py
@@ -6,7 +6,7 @@ from rotagaporp.chebyshev import Chebyshev
 # from rotagaporp.symplectic import Symplectic
 from rotagaporp.systems import LennardJones, MPPS1D, MPPS3D
 from rotagaporp.mpliouville import MPLPQP
-from rotagaporp.liouville import LiouvillePowersQP
+from rotagaporp.liouville import SPLPQP
 
 propagator = Chebyshev
 # propagator = Symplectic
@@ -15,7 +15,7 @@ propagator = Chebyshev
 params_2p = {'tstart': 0.0, 'tend': 2.0, 'tstep': 0.05, 'nterms': 4,
              'liouville': MPLPQP}
 params_1p = {'tstart': 0.0, 'tend': 2.0, 'tstep': 0.05, 'nterms': 4,
-             'liouville': LiouvillePowersQP}
+             'liouville': SPLPQP}
 
 M = [2.0, 2.0]
 syspar_3d = {'symbols': ['0x:z', '1x:z'], 'q0': [[0, 0, 0], [2, 0, 0]],
diff --git a/examples/test_cheb_mo_1p_1d_twostep.py b/examples/test_cheb_mo_1p_1d_twostep.py
index 18129790e9375bbfab62e03e9ab9c6a085866e46..afcd77b0b27228f5032fe31ce408b71fbede804d 100644
--- a/examples/test_cheb_mo_1p_1d_twostep.py
+++ b/examples/test_cheb_mo_1p_1d_twostep.py
@@ -4,8 +4,9 @@ import matplotlib.pyplot as plt
 from rotagaporp.chebyshev import Chebyshev, TwoStepChebyshev
 from rotagaporp.symplectic import Symplectic
 from rotagaporp.systems import Morse
+from liouville import SPLPQP
 
-params = {'tstart': 0., 'tend': 500., 'tstep': 0.05, 'nterms': 4, 'tqdm': True}
+params = {'tstart': 0., 'tend': 500., 'tstep': 0.05, 'nterms': 3, 'tqdm': True}
 syspar0 = {'q0': 3., 'p0': 0.}
 system = Morse(**syspar0)
 
@@ -43,8 +44,9 @@ edrift_ch = ch_prop.er
 # two-step propagator
 params['q_1'] = syspar0['q0']
 params['p_1'] = syspar0['p0']
+params['liouville'] = SPLPQP
 params['parity'] = 0
-# params['signed'] = False
+params['signed'] = False
 ts_prop = TwoStepChebyshev(syst=system, **params)
 ts_prop.propagate()
 time_ts, q_ts, p_ts = ts_prop.get_trajectory()
diff --git a/examples/test_cheb_mo_2p_xd.py b/examples/test_cheb_mo_2p_xd.py
index e4d32219f0490f4cf6ce682ba602a2736aaadfb6..2edab76b5abd80c2ac5ebf22927f474313efc753 100644
--- a/examples/test_cheb_mo_2p_xd.py
+++ b/examples/test_cheb_mo_2p_xd.py
@@ -6,7 +6,7 @@ from rotagaporp.chebyshev import Chebyshev
 # from rotagaporp.symplectic import Symplectic
 from rotagaporp.systems import Morse, MPPS1D, MPPS3D
 from rotagaporp.mpliouville import MPLPQP
-from rotagaporp.liouville import LiouvillePowersQP
+from rotagaporp.liouville import SPLPQP
 
 propagator = Chebyshev
 # propagator = Symplectic
@@ -15,7 +15,7 @@ propagator = Chebyshev
 params_2p = {'tstart': 0.0, 'tend': 10., 'tstep': 0.1, 'nterms': 4,
              'liouville': MPLPQP}
 params_1p = {'tstart': 0.0, 'tend': 10., 'tstep': 0.1, 'nterms': 4,
-             'liouville': LiouvillePowersQP}
+             'liouville': SPLPQP}
 
 M = [2.0, 2.0]
 syspar_3d = {'symbols': ['0x:z', '1x:z'], 'q0': [[1, 0, 0], [4, 0, 0]],
diff --git a/examples/time_1p_nr_cheb.py b/examples/time_1p_nr_cheb.py
index 6d3d24e47d04cfaa0756fd1a62d0321411d54a8a..85d66f8cc40bf9f18ecce9c0f62514001eb5acab 100644
--- a/examples/time_1p_nr_cheb.py
+++ b/examples/time_1p_nr_cheb.py
@@ -2,7 +2,7 @@
 import time
 import sympy as sp
 import numpy as np
-from rotagaporp.liouville import LiouvillePowersNR, LiouvillePowersQP
+from rotagaporp.liouville import SPLPNR, SPLPQP
 from rotagaporp.systems import Harmonic, Anharmonic, Morse, LennardJones
 
 nterms = 16
@@ -11,14 +11,14 @@ qval = 5.
 pval = -1.
 
 ts = time.time()
-lp_nr = LiouvillePowersNR(nterms, syst, recursion='chebyshev', sign=1)
+lp_nr = SPLPNR(nterms, syst, recursion='chebyshev', sign=1)
 te = time.time()
-print('preparation time for LiouvillePowersNR:', te-ts)
+print('preparation time for SPLPNR:', te-ts)
 
 ts = time.time()
-lp_qp = LiouvillePowersQP(nterms, syst, recursion='chebyshev', sign=1)
+lp_qp = SPLPQP(nterms, syst, recursion='chebyshev', sign=1)
 te = time.time()
-print("preparation time for LiouvillePowersQP:", te-ts)
+print("preparation time for SPLPQP:", te-ts)
 
 qvec_nr, pvec_nr = lp_nr.get_val_float(qval, pval)
 qvec_qp, pvec_qp = lp_qp.get_val_float(qval, pval)
@@ -32,10 +32,10 @@ ts = time.time()
 for q, p in zip(qarr, parr):
     lp_nr.get_val_float(q, p)
 te = time.time()
-print("propagation time for LiouvillePowersNR:", te-ts)
+print("propagation time for SPLPNR:", te-ts)
 
 ts = time.time()
 for q, p in zip(qarr, parr):
     lp_qp.get_val_float(q, p)
 te = time.time()
-print("propagation time for LiouvillePowersQP:", te-ts)
+print("propagation time for SPLPQP:", te-ts)
diff --git a/examples/time_1p_nr_newt.py b/examples/time_1p_nr_newt.py
index 52db0b8db37eea7da96898ef0a38979512f20373..cfca76a7d094b4563f005406c0b93ba666127d28 100644
--- a/examples/time_1p_nr_newt.py
+++ b/examples/time_1p_nr_newt.py
@@ -2,7 +2,7 @@
 import time
 import sympy as sp
 import numpy as np
-from rotagaporp.liouville import LiouvillePowersNR, LiouvillePowersQP
+from rotagaporp.liouville import SPLPNR, SPLPQP
 from rotagaporp.systems import Harmonic, Anharmonic, Morse, LennardJones
 from rotagaporp.newtonian import leja_points_ga
 
@@ -14,16 +14,16 @@ pval = -1.
 lambdas, scaling = leja_points_ga(nterms)
 
 ts = time.time()
-lp_nr = LiouvillePowersNR(nterms, syst, recursion='newton', nodes=lambdas,
+lp_nr = SPLPNR(nterms, syst, recursion='newton', nodes=lambdas,
                           scale=1./scaling)
 te = time.time()
-print('preparation time for LiouvillePowersNR:', te-ts)
+print('preparation time for SPLPNR:', te-ts)
 
 ts = time.time()
-lp_qp = LiouvillePowersQP(nterms, syst, recursion='newton', nodes=lambdas,
+lp_qp = SPLPQP(nterms, syst, recursion='newton', nodes=lambdas,
                           scale=1./scaling)
 te = time.time()
-print("preparation time for LiouvillePowersQP:", te-ts)
+print("preparation time for SPLPQP:", te-ts)
 
 assert all(nr.equals(qp) for nr, qp in zip(lp_nr.ilnpexpr, lp_qp.pobj.Lf))
 
@@ -39,10 +39,10 @@ ts = time.time()
 for q, p in zip(qarr, parr):
     lp_nr.get_val_float(q, p)
 te = time.time()
-print("propagation time for LiouvillePowersNR:", te-ts)
+print("propagation time for SPLPNR:", te-ts)
 
 ts = time.time()
 for q, p in zip(qarr, parr):
     lp_qp.get_val_float(q, p)
 te = time.time()
-print("propagation time for LiouvillePowersQP:", te-ts)
+print("propagation time for SPLPQP:", te-ts)
diff --git a/rotagaporp/chebyshev.py b/rotagaporp/chebyshev.py
index eea2d63f41d725f69597c2542a51f43434fdde32..e3779b6c50f94ffc0c7111c67f1b5eeb51f32b45 100644
--- a/rotagaporp/chebyshev.py
+++ b/rotagaporp/chebyshev.py
@@ -101,22 +101,9 @@ class TwoStepChebyshev(TwoStepPolynomialPropagator):
         self.nterms = int(np.ceil(alpha)) if nterms is None else nterms
         self.efficiency = alpha/self.nterms
         bf = besself(self.fpprec, signed, prec=self.prec)
+        assert isinstance(signed, bool)
         sign = -1 if signed else 1
         assert self.substep is None, 'substep not implemented'
         self.coeffs = 2.*cheb_coef(bf, self.nterms, alpha)[self.parity::2]
-        self.set_polynomial(system=self.syst, scale=2./self.delta,
-                            recursion='chebyshev', sign=sign)
-
-    def step_nopbc(self, time, q, p):
-        """ perform a time step with initial coordinate and momentum """
-        # the get_val_float() method has to be adapted to evaluate only
-        # either the odd or the even powers
-        qvecaux, pvecaux = self.iln.get_val_float(q, p)
-        qvec = qvecaux[self.parity::2]
-        pvec = pvecaux[self.parity::2]
-        #
-        qt = np.dot(self.coeffs, qvec) + self.prefact*self.q_1
-        pt = np.dot(self.coeffs, pvec) + self.prefact*self.p_1
-        self.q_1 = q
-        self.p_1 = p
-        return (qt, pt)
+        self.set_polynomial(system=self.syst, scale=2./self.delta, sign=sign,
+                            recursion='chebyshev', parity=self.parity)
diff --git a/rotagaporp/liouville.py b/rotagaporp/liouville.py
index 5493767d44eed2940513ff5ffc80d0a9720c25f3..78718352019be7a5cb12d54765fd9510562e8b81 100644
--- a/rotagaporp/liouville.py
+++ b/rotagaporp/liouville.py
@@ -1,6 +1,7 @@
 """ Class to evaluate the powers of the classical Liouville operator iL """
 import sympy as sp
 import numpy as np
+from generic import _float
 
 q = sp.Symbol('q')
 p = sp.Symbol('p')
@@ -99,6 +100,7 @@ class LiouvillePowers:
 
 
 class LiouvillePowersQP:
+    """ One-particle Liouville applied to phase space variables q and p """
     def __init__(self, nterms, system, **kwargs):
         self.qobj = LiouvillePowers(nterms, system.hamiltonian, system.q,
                                     system.p, function=system.q, **kwargs)
@@ -106,11 +108,123 @@ class LiouvillePowersQP:
                                     system.p, function=system.p, **kwargs)
 
     def get_val_float(self, qv, pv):
-        """ evaluates (iL)^n q and (iL)^n p for given values of q and p """
+        """ evaluates the expressions for given values of q and p """
         return (self.qobj.get_val_float(qv, pv), self.pobj.get_val_float(qv, pv))
 
+class SPLP:
+    """ Polynomials and monomials of single-particle Liouville operator L """
 
-class LiouvillePowersNR(LiouvillePowers):
+    def __init__(self, nterms, hamiltonian, coordinate, momentum, function,
+                 scale=1, shift=0, recursion='taylor', nodes=None, sign=None,
+                 parity=None, fpprec='fixed'):
+        """ * nterms: number of polynomials, the highest order (nterms-1)
+            * hamiltonian: expression of the system Hamiltonian
+            * coordinate: coordinate symbol as in the Hamiltonian expression
+            * momentum: momentum symbol as in the Hamiltonian expression
+            * function: a system variable to which iL is applied
+            * scale: a scaling factor for L
+            * shift: a shift for L that is always 0, deprecated argument
+            * nodes: a list of Newton interpolation points
+            * sign: the sign in the Chebyshev polynomial recursion formula
+               > sign = +1 for Chebyshev polynomials with imaginary argument
+               > sign = -1 for Chebyshev polynomials with real argument
+            * parity: parity of the Chebyshev polynomials: 0: even, 1: odd """
+
+        self.nterms = nterms
+        self.H = hamiltonian
+        self.q = coordinate
+        self.p = momentum
+        self.f = function
+        self.fpprec = fpprec
+        self.sign = sign
+        self.scale = scale
+        self.nodes = nodes
+        self.parity = parity
+        self.A = sp.diff(self.H, self.q).doit()*self.scale
+        self.B = sp.diff(self.H, self.p).doit()*self.scale
+        getattr(self, recursion)()
+
+    def poisson(self, phi):
+        """ evaluate the Poisson bracket applied to variable phi, iL.phi """
+        alf = sp.diff(phi, self.q).doit()
+        blf = sp.diff(phi, self.p).doit()
+        return self.B*alf - self.A*blf
+
+    def chebyshev(self):
+        """ evaluate the Chebyshev polynomials with argument iL """
+        assert self.sign in (-1, 1)
+        phi0 = self.f
+        phi1 = self.poisson(self.f)
+        if self.parity is None:
+            self.Lf = [phi0, phi1]
+            for k in range(2, self.nterms):
+                phik = 2*self.poisson(self.Lf[k-1]) + self.sign*self.Lf[k-2]
+                self.Lf.append(phik.expand())
+        else:
+            assert self.parity in (0, 1)
+            assert (self.nterms-1)%2 == self.parity
+            if self.parity == 0:
+                phi2 = 2*self.poisson(phi1) + self.sign*self.f
+                self.Lf = [phi0, phi2]
+            else:
+                phi3 = 4*self.poisson(self.poisson(phi1)) + self.sign*3*phi1
+                self.Lf = [phi1, phi3]
+            for k in range(2, (self.nterms-1)//2+1):
+                Lsq_psi_1 = self.poisson(self.poisson(self.Lf[k-1]))
+                psik = 4*Lsq_psi_1 + self.sign*2*self.Lf[k-1] - self.Lf[k-2]
+                self.Lf.append(psik.expand())
+
+    def newton(self):
+        """ evaluate the Newton basis polynomials with argument iL """
+        assert self.nodes is not None
+        self.Lf = [self.f]
+        for n in range(1, self.nterms):
+            expr = self.poisson(self.Lf[n-1]) - self.nodes[n-1]*self.Lf[n-1]
+            self.Lf.append(expr.expand())
+
+    def taylor(self):
+        """ evaluate the monomials (iL)^n.f for the Liouville operator L """
+        self.Lf = [self.f]
+        for n in range(1, self.nterms):
+            self.Lf.append(self.poisson(self.Lf[n-1]).expand())
+
+    def get_val_float(self, qval, pval):
+        """ evaluate the symbolic expressions for given values of q and p """
+        repl = {self.q: qval, self.p: pval}
+        auxfunc = _float(self.fpprec, lambda x, y: x.xreplace(y))
+        return [auxfunc(expr, repl) for expr in self.Lf]
+
+    def __repr__(self):
+        """ string representation of the object in terms of A_k and B_k """
+        A = [sp.diff(self.H, self.q, n) for n in range(self.nterms)]
+        B = [sp.diff(self.H, self.p, n) for n in range(self.nterms)]
+        repl = [(sp.S.Zero, sp.Symbol('0'))]
+        for n in reversed(range(self.nterms)):
+            repl.append((A[n], sp.Symbol('A'+str(n))))
+            repl.append((B[n], sp.Symbol('B'+str(n))))
+        if self.f != self.q and self.f != self.p:
+            aa = [sp.diff(self.f, self.q, n) for n in range(self.nterms)]
+            bb = [sp.diff(self.f, self.p, n) for n in range(self.nterms)]
+            for n in reversed(range(1, self.nterms)):
+                repl.append((aa[n], sp.Symbol('a'+str(n))))
+                repl.append((bb[n], sp.Symbol('b'+str(n))))
+        return 'P_n (f: %s): %s' % (self.f, [e.subs(repl) for e in self.Lf])
+
+
+class SPLPQP:
+    """ Polynomials / monomials of SP Liouville operator applied to q and p """
+    def __init__(self, nterms, system, **kwargs):
+        self.qobj = SPLP(nterms, system.hamiltonian, system.q, system.p,
+                         function=system.q, **kwargs)
+        self.pobj = SPLP(nterms, system.hamiltonian, system.q, system.p,
+                         function=system.p, **kwargs)
+
+    def get_val_float(self, q, p):
+        """ evaluate the symbolic expressions for given values of q and p """
+        return (self.qobj.get_val_float(q, p), self.pobj.get_val_float(q, p))
+
+
+class SPLPNR(SPLP):
     """ use the identity (iL)^n q == (iL)^{n-1} p which is valid if
         H(q, p) = p^2/2 + V(q) and non-recursive Chebyshev polynomial
         expansion or Newtonian polynomial interpolation """
diff --git a/rotagaporp/propagators.py b/rotagaporp/propagators.py
index b8c2e8b50ccc8a4b7af802333cf6e24982651dda..6d1ad8442cf7edcc1256534c251f62a1eecd634c 100644
--- a/rotagaporp/propagators.py
+++ b/rotagaporp/propagators.py
@@ -90,12 +90,12 @@ class Propagator:
         self.er = np.array(func(self.en, self.en0), dtype=float)
 
 
-from liouville import LiouvillePowersQP
+from liouville import SPLPQP
 
 class PolynomialPropagator(Propagator):
     """ Base class for polynomial classical propagators """
     name = 'polynomial'
-    def __init__(self, liouville=LiouvillePowersQP, liou_params={},
+    def __init__(self, liouville=SPLPQP, liou_params={},
                  restart=False, restart_file='propag.pkl', fpprec='fixed',
                  prec=None, **kwargs):
         super().__init__(**kwargs)
@@ -152,9 +152,7 @@ class PolynomialPropagator(Propagator):
 
 class TwoStepPolynomialPropagator(PolynomialPropagator):
     """ Base class for two-step polynomial classical propagators """
-
     name = 'two-step polynomial'
-
     def __init__(self, q_1, p_1, parity=0, **kwargs):
         assert parity in (0, 1)
         super().__init__(**kwargs)
@@ -162,3 +160,12 @@ class TwoStepPolynomialPropagator(PolynomialPropagator):
         self.prefact = 2*parity-1
         self.q_1 = q_1
         self.p_1 = p_1
+
+    def step_nopbc(self, time, q, p):
+        """ perform a time step with initial coordinate and momentum """
+        qvec, pvec = self.iln.get_val_float(q, p)
+        qt = np.dot(self.coeffs, qvec) + self.prefact*self.q_1
+        pt = np.dot(self.coeffs, pvec) + self.prefact*self.p_1
+        self.q_1 = q
+        self.p_1 = p
+        return (qt, pt)
diff --git a/tests/sp_tests.py b/tests/sp_tests.py
index 9f31b5d0c4d034b9f35eecf854306c147b1d5110..949e03c632ede85000fed18776803f464a78ed3e 100644
--- a/tests/sp_tests.py
+++ b/tests/sp_tests.py
@@ -3,7 +3,8 @@ import unittest
 import numpy as np
 import sympy as sp
 from rotagaporp.liouville import q, p
-from rotagaporp.liouville import LiouvillePowers, LiouvillePowersQP, LiouvillePowersNR
+from rotagaporp.liouville import LiouvillePowers, LiouvillePowersQP
+from rotagaporp.liouville import SPLP, SPLPQP, SPLPNR
 from rotagaporp.symplectic import Symplectic
 from rotagaporp.chebyshev import Chebyshev, TwoStepChebyshev
 from rotagaporp.newtonian import Newtonian
@@ -134,8 +135,8 @@ class LiouvillePowersTest(unittest.TestCase):
                 assert direct == recurs
 
 
-class LiouvillePowersNRTest(unittest.TestCase):
-    """ Test the LiouvillePowersNR class """
+class SPLPNRTest(unittest.TestCase):
+    """ Test the SPLPNR class """
 
     def test_nrcheb_symbolic(self):
         """ recursive and non-recursive Chebyshev expansions: symbolic """
@@ -145,11 +146,11 @@ class LiouvillePowersNRTest(unittest.TestCase):
             p = p
             hamiltonian = p**2/2 + sp.Function('V', real=True)(q)
         syst = system()
-        lp_nr = LiouvillePowersNR(nterms, syst, recursion='chebyshev', sign=1)
-        lp_tr = LiouvillePowersQP(nterms, syst, recursion='taylor')
+        lp_nr = SPLPNR(nterms, syst, recursion='chebyshev', sign=1)
+        lp_tr = SPLPQP(nterms, syst, recursion='taylor')
         self.assertListEqual(lp_tr.qobj.Lf, lp_nr.ilnq)
         self.assertListEqual(lp_tr.pobj.Lf, lp_nr.ilnp)
-        lp_cr = LiouvillePowersQP(nterms, syst, recursion='chebyshev', sign=1)
+        lp_cr = SPLPQP(nterms, syst, recursion='chebyshev', sign=1)
         self.assertListEqual(lp_cr.qobj.Lf, lp_nr.ilnqexpr.tolist())
         self.assertListEqual(lp_cr.pobj.Lf, lp_nr.ilnpexpr.tolist())
 
@@ -157,8 +158,8 @@ class LiouvillePowersNRTest(unittest.TestCase):
         """ recursive and non-recursive Chebyshev expansions: numeric """
         nterms = 12
         syst = Harmonic()
-        lp_nr = LiouvillePowersNR(nterms, syst, recursion='chebyshev', sign=1)
-        lp_cr = LiouvillePowersQP(nterms, syst, recursion='chebyshev', sign=1)
+        lp_nr = SPLPNR(nterms, syst, recursion='chebyshev', sign=1)
+        lp_cr = SPLPQP(nterms, syst, recursion='chebyshev', sign=1)
         qptest = (1., -1.)
         qvec_nr, pvec_nr = lp_nr.get_val_float_direct(*qptest)
         qvec_cr, pvec_cr = lp_cr.get_val_float(*qptest)
@@ -177,13 +178,13 @@ class LiouvillePowersNRTest(unittest.TestCase):
             hamiltonian = p**2/2 + sp.Function('V', real=True)(q)
         syst = system()
         lambdas, scaling = leja_points_ga(nterms)
-        lp_nr = LiouvillePowersNR(nterms, syst, recursion='newton',
+        lp_nr = SPLPNR(nterms, syst, recursion='newton',
                                   nodes=lambdas, scale=1./scaling)
-        lp_tr = LiouvillePowersQP(nterms, syst, recursion='taylor',
+        lp_tr = SPLPQP(nterms, syst, recursion='taylor',
                                   scale=1./scaling)
         self.assertListEqual(lp_tr.qobj.Lf, lp_nr.ilnq)
         self.assertListEqual(lp_tr.pobj.Lf, lp_nr.ilnp)
-        lp_cr = LiouvillePowersQP(nterms, syst, recursion='newton',
+        lp_cr = SPLPQP(nterms, syst, recursion='newton',
                                   nodes=lambdas, scale=1./scaling)
         qchck = all(n.equals(r) for n, r in zip(lp_nr.ilnqexpr, lp_cr.qobj.Lf))
         self.assertTrue(qchck)
@@ -195,9 +196,9 @@ class LiouvillePowersNRTest(unittest.TestCase):
         nterms = 12
         syst = LennardJones()
         lambdas, scaling = leja_points_ga(nterms)
-        lp_nr = LiouvillePowersNR(nterms, syst, recursion='newton',
+        lp_nr = SPLPNR(nterms, syst, recursion='newton',
                                   nodes=lambdas, scale=1./scaling)
-        lp_cr = LiouvillePowersQP(nterms, syst, recursion='newton',
+        lp_cr = SPLPQP(nterms, syst, recursion='newton',
                                   nodes=lambdas, scale=1./scaling)
         qptest = (5., -1.)
         qvec_nr, pvec_nr = lp_nr.get_val_float_direct(*qptest)
@@ -209,6 +210,146 @@ class LiouvillePowersNRTest(unittest.TestCase):
         self.assertTrue(np.allclose(pvec_nr, pvec_cr))
 
 
+class SPLPTest(unittest.TestCase):
+    """ Tests for the SPLP class """
+
+    hamsplit = sp.Function('V', real=True)(q)+sp.Function('T', real=True)(p)
+    hamgener = sp.Function('H', real=True)(q, p)
+    funsplit = sp.Function('fq', real=True)(q)+sp.Function('fp', real=True)(p)
+    fungener = sp.Function('f', real=True)(q, p)
+
+    def test_liouvillepower_expr(self):
+        """ expression tests """
+        ilnp = SPLP(4, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=p)
+        self.assertEqual(ilnp.Lf, [p, -q, -p, q])
+        ilnq = SPLP(4, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=q)
+        self.assertEqual(ilnq.Lf, [q, p, -q, -p])
+        ilnf = SPLP(4, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=p)
+        self.assertEqual(ilnf.Lf, [p, -q, -p, q])
+        ilnf = SPLP(2, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=q)
+        self.assertEqual(ilnf.Lf, [q, p])
+
+    def test_liouvillepower_eval(self):
+        """ numeric evaluation tests """
+        ilnp = SPLP(4, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=p)
+        self.assertEqual(ilnp.get_val_float(1, 1), [1, -1, -1, 1])
+        hamiltonian = (p**2 + q**4)/2 - q**2
+        ilnq = SPLP(4, hamiltonian=hamiltonian, coordinate=q, momentum=p,
+                    function=q)
+        ref_expr = [q, p, -2*q**3 + 2*q, -6*p*q**2 + 2*p]
+        ref_val = [1, 1, 0, -4]
+        self.assertEqual(ilnq.Lf, ref_expr)
+        self.assertEqual(ilnq.get_val_float(1, 1), ref_val)
+
+    def test_liouvillepower_repr_qp(self):
+        """ symbols output tests for iL applied to variables q and p """
+        ilnq = SPLP(6, self.hamsplit, coordinate=q, momentum=p, function=q)
+        ilnp = SPLP(6, self.hamsplit, coordinate=q, momentum=p, function=p)
+        ilnq_ref = (r'P_n (f: q): [q, B1, -A1*B2, A1**2*B3 - A2*B1*B2, '
+                    r'-A1**3*B4 + 3*A1*A2*B1*B3 + A1*A2*B2**2 - A3*B1**2*B2, '
+                    r'A1**4*B5 - 6*A1**2*A2*B1*B4 - 5*A1**2*A2*B2*B3 + '
+                    r'4*A1*A3*B1**2*B3 + 3*A1*A3*B1*B2**2 + 3*A2**2*B1**2*B3 '
+                    r'+ A2**2*B1*B2**2 - A4*B1**3*B2]')
+        ilnp_ref = (r'P_n (f: p): [p, -A1, -A2*B1, A1*A2*B2 - A3*B1**2, '
+                    r'-A1**2*A2*B3 + 3*A1*A3*B1*B2 + A2**2*B1*B2 - A4*B1**3, '
+                    r'A1**3*A2*B4 - 4*A1**2*A3*B1*B3 - 3*A1**2*A3*B2**2 - '
+                    r'3*A1*A2**2*B1*B3 - A1*A2**2*B2**2 + 6*A1*A4*B1**2*B2 + '
+                    r'5*A2*A3*B1**2*B2 - A5*B1**4]')
+        self.assertEqual(repr(ilnq), ilnq_ref)
+        self.assertEqual(repr(ilnp), ilnp_ref)
+
+    def test_liouvillepower_repr_f(self):
+        """ symbols output tests for iL applied to f = fq(q) + fp(p) """
+        ilnf = SPLP(5, self.hamsplit, coordinate=q, momentum=p,
+                    function=self.funsplit)
+        ilnf_ref = (r'P_n (f: fp(p) + fq(q)): [fp(p) + fq(q), -A1*b1 + B1*a1'
+                    r', A1**2*b2 - A1*B2*a1 - A2*B1*b1 + B1**2*a2, -A1**3*b3 '
+                    r'+ A1**2*B3*a1 + 3*A1*A2*B1*b2 + A1*A2*B2*b1 - 3*A1*B1*B'
+                    r'2*a2 - A2*B1*B2*a1 - A3*B1**2*b1 + B1**3*a3, A1**4*b4 -'
+                    r' A1**3*B4*a1 - 6*A1**2*A2*B1*b3 - 4*A1**2*A2*B2*b2 - A1'
+                    r'**2*A2*B3*b1 + 4*A1**2*B1*B3*a2 + 3*A1**2*B2**2*a2 + 3*'
+                    r'A1*A2*B1*B3*a1 + A1*A2*B2**2*a1 + 4*A1*A3*B1**2*b2 + 3*'
+                    r'A1*A3*B1*B2*b1 - 6*A1*B1**2*B2*a3 + 3*A2**2*B1**2*b2 + '
+                    r'A2**2*B1*B2*b1 - 4*A2*B1**2*B2*a2 - A3*B1**2*B2*a1 - A4'
+                    r'*B1**3*b1 + B1**4*a4]')
+        self.assertEqual(repr(ilnf), ilnf_ref)
+
+    def test_liouvillepower_symb(self):
+        """ numeric evaluation tests """
+        ilnq = SPLP(4, hamiltonian=(q**2+p**2)/2, coordinate=q, momentum=p,
+                    function=q)
+        self.assertEqual(ilnq.get_val_float(1, 1), [1, 1, -1, -1])
+
+    def test_qp_symmetry(self):
+        """ test iL^n q == iL^(n-1) p when kinetic energy is T(p) = p^2/2 """
+
+        nterms = 5
+        ham = p**2/2 + sp.Function('V', real=True)(q)
+        lpq_t = SPLP(nterms, ham, coordinate=q, momentum=p, function=q,
+                     recursion='taylor')
+        lpp_t = SPLP(nterms, ham, coordinate=q, momentum=p, function=p,
+                     recursion='taylor')
+        for n in range(1, nterms):
+            self.assertEqual(lpq_t.Lf[n], lpp_t.Lf[n-1])
+
+        # no symmetry if kinetic energy not explicitly defined, T(p)
+        lpq_t = SPLP(nterms, self.hamsplit, coordinate=q, momentum=p,
+                     function=q, recursion='taylor')
+        lpp_t = SPLP(nterms, self.hamsplit, coordinate=q, momentum=p,
+                     function=p, recursion='taylor')
+        for n in range(1, nterms):
+            self.assertNotEqual(lpq_t.Lf[n], lpp_t.Lf[n-1])
+
+    def test_direct_recursive(self):
+        """ check that the Chebyshev recurrence relations
+            T_n(iL) f = 2 iL T_{n-1}(iL) f -/+ T_{n-2}(iL) f and the expansion
+            T_n(iL) f = sum_{k=0}^n C^(n,-/+)_k (iL)^k f are equal """
+
+        nterms = 5
+        cnk = cnk_chebyshev_T2
+        ilnt = SPLP(nterms, self.hamgener, coordinate=q, momentum=p,
+                    function=self.fungener, recursion='taylor')
+        for signed in (True, False):
+            sign = -1 if signed else 1
+            ilnc = SPLP(nterms, self.hamgener, coordinate=q, momentum=p,
+                        function=self.fungener, recursion='chebyshev',
+                        sign=sign)
+            for n in range(nterms):
+                direct = sum(ilnt.Lf[k]*cnk(n, k, signed) for k in range(n+1))
+                self.assertEqual(direct, ilnc.Lf[n])
+
+    def test_chebyshev_parity(self):
+        """ compare Chebyshev polynomials of same parity with and without
+            parity parameter for different sign, valid for any H and f """
+
+        nterms = 7
+        # 102 seconds for nterms=5
+        # hamiltonian, function = self.hamgener, self.fungener
+        # 11 seconds for nterms=5
+        # hamiltonian, function = self.hamsplit, self.funsplit
+        # 3 seconds for nterms=7
+        hamiltonian, function = self.hamsplit, q
+        for sign in (-1, 1):
+            ilnall = SPLP(nterms, hamiltonian, q, p, function,
+                          recursion='chebyshev', sign=sign, parity=None)
+            ilneven = SPLP(nterms, hamiltonian, q, p, function,
+                           recursion='chebyshev', sign=sign, parity=0)
+            self.assertEqual(ilnall.Lf[0].factor(), ilneven.Lf[0].factor())
+            self.assertEqual(ilnall.Lf[2].factor(), ilneven.Lf[1].factor())
+            self.assertEqual(ilnall.Lf[4].factor(), ilneven.Lf[2].factor())
+            self.assertEqual(ilnall.Lf[6].factor(), ilneven.Lf[3].factor())
+            ilnodd = SPLP(nterms-1, hamiltonian, q, p, function,
+                          recursion='chebyshev', sign=sign, parity=1)
+            self.assertEqual(ilnall.Lf[1].factor(), ilnodd.Lf[0].factor())
+            self.assertEqual(ilnall.Lf[3].factor(), ilnodd.Lf[1].factor())
+            self.assertEqual(ilnall.Lf[5].factor(), ilnodd.Lf[2].factor())
+
+
 class ChebyshevPropagatorTest(unittest.TestCase):
     """ Tests for the Chebyshev polynomial propagator """
 
@@ -309,10 +450,10 @@ class ChebyshevPropagatorTest(unittest.TestCase):
         self.assertTrue(np.allclose(ptu, pts, rtol=1e-7))
 
     def chebyshev_propagator_nonrecursive_test(self):
-        """ test Chebyshev propagator with non-recursive LiouvillePowersNR """
+        """ test Chebyshev propagator with non-recursive SPLPNR """
         syst = Harmonic(**self.syspar)
         params = self.params.copy()
-        params['liouville'] = LiouvillePowersNR
+        params['liouville'] = SPLPNR
         prop_nr = Chebyshev(syst=syst, **params)
         prop_nr.propagate()
         prop_nr.analyse()
@@ -326,7 +467,8 @@ class ChebyshevPropagatorTest(unittest.TestCase):
 class TwoStepChebyshevPropagatorTest(unittest.TestCase):
     """ Tests for the two-step Chebyshev polynomial propagator """
 
-    params = {'tstart': 0.0, 'tend': 5.0, 'tstep': 0.2, 'nterms': 8}
+    params = {'tstart': 0.0, 'tend': 5.0, 'tstep': 0.2, 'nterms': 7,
+              'liouville': SPLPQP}
     syspar = {'q0': 1.1, 'p0': 0.0}
 
     def chebyshev_propagator_ballistic_and_harmonic_test(self):
@@ -355,10 +497,12 @@ class TwoStepChebyshevPropagatorTest(unittest.TestCase):
         params = self.params.copy()
         params['q_1'] = qinit[0]
         params['p_1'] = pinit[0]
-        for parity in (0, 1):
+        for parity, nterms in zip((0, 1), (7, 8)):
             for signed in (True, False):
-                prop = TwoStepChebyshev(syst=syst, parity=parity,
-                                        signed=signed, **params)
+                params['nterms'] = nterms
+                params['parity'] = parity
+                params['signed'] = signed
+                prop = TwoStepChebyshev(syst=syst, **params)
                 prop.propagate()
                 prop.analyse()
                 self.assertLess(np.max(np.fabs(prop.er)), 1e-8)
@@ -370,7 +514,7 @@ class TwoStepChebyshevPropagatorTest(unittest.TestCase):
     def chebyshev_propagator_lj_test(self):
         """ test with a particle in Lennard-Jones potential """
         syspar = {'p0': -1.0, 'q0': 2}
-        params = {'tstart': 0.0, 'tend': 1.8, 'tstep': 0.02, 'nterms': 6}
+        params = {'tstart': 0.0, 'tend': 1.8, 'tstep': 0.02, 'nterms': 5}
         syst = LennardJones(**syspar)
         ref_prop = Chebyshev(syst=syst, **params)
         ref_prop.propagate()
@@ -379,10 +523,13 @@ class TwoStepChebyshevPropagatorTest(unittest.TestCase):
         params['q_1'] = q_ref[0]
         params['p_1'] = p_ref[0]
         params['tstart'] = params['tstart'] + params['tstep']
-        for parity in (0, 1):
+        params['liouville'] = SPLPQP
+        for parity, nterms in zip((0, 1), (5, 6)):
             for signed in (False, True):
-                prop = TwoStepChebyshev(syst=syst, parity=parity,
-                                        signed=signed, **params)
+                params['nterms'] = nterms
+                params['parity'] = parity
+                params['signed'] = signed
+                prop = TwoStepChebyshev(syst=syst, **params)
                 prop.propagate()
                 prop.analyse()
                 self.assertLess(np.max(np.fabs(prop.er)), 1e-3)
@@ -722,8 +869,9 @@ class ChebyshevAssessmentTest(unittest.TestCase):
     def chebyshev_shift_test(self):
         """ chebyshev propagator with scale and shift """
         syst = Harmonic(q0=1., p0=0.)
-        params = {'delta': 3., 'lambda_min': -2., 'nterms': 16,
-                  'signed': False, 'tstart': 0., 'tend': 10.0, 'tstep': 0.5}
+        params = {'delta': 3., 'lambda_min': -2., 'nterms': 16, 'tstart': 0.,
+                  'tend': 10.0, 'tstep': 0.5, 'liouville': LiouvillePowersQP,
+                  'signed': False}
         prop = Chebyshev(syst=syst, **params)
         prop.propagate()
         prop.analyse()