packages feed

hspray 0.2.5.0 → 0.2.6.0

raw patch · 5 files changed

+837/−217 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Math.Algebra.Hspray: (^/^) :: (Eq a, C a) => Polynomial a -> Polynomial a -> RatioOfPolynomials a
+ Math.Algebra.Hspray: collinearSprays :: (Eq a, C a) => Spray a -> Spray a -> Bool
+ Math.Algebra.Hspray: numberOfVariables :: Spray a -> Int
+ Math.Algebra.Hspray: prettyNumSpray :: (Num a, Ord a, Show a) => Spray a -> String
+ Math.Algebra.Hspray: prettyNumSpray' :: (Num a, Ord a, Show a) => Spray a -> String
+ Math.Algebra.Hspray: prettyNumSprayX1X2X3 :: (Num a, Ord a, Show a) => String -> Spray a -> String
+ Math.Algebra.Hspray: prettyNumSprayXYZ :: (Num a, Ord a, Show a) => [String] -> Spray a -> String
+ Math.Algebra.Hspray: prettyQSpray :: QSpray -> String
+ Math.Algebra.Hspray: prettyQSpray' :: QSpray' -> String
+ Math.Algebra.Hspray: prettyQSpray'' :: QSpray -> String
+ Math.Algebra.Hspray: prettyQSpray''' :: QSpray' -> String
+ Math.Algebra.Hspray: prettyQSprayX1X2X3 :: String -> QSpray -> String
+ Math.Algebra.Hspray: prettyQSprayX1X2X3' :: String -> QSpray' -> String
+ Math.Algebra.Hspray: prettyQSprayXYZ :: [String] -> QSpray -> String
+ Math.Algebra.Hspray: prettyQSprayXYZ' :: [String] -> QSpray' -> String
+ Math.Algebra.Hspray: prettySprayX1X2X3 :: Show a => String -> Spray a -> String
+ Math.Algebra.Hspray: prettySymbolicQSpray' :: String -> SymbolicQSpray -> String
+ Math.Algebra.Hspray: prettySymbolicQSprayX1X2X3 :: String -> String -> SymbolicQSpray -> String
+ Math.Algebra.Hspray: prettySymbolicQSprayXYZ :: String -> [String] -> SymbolicQSpray -> String
+ Math.Algebra.Hspray: prettySymbolicSpray' :: (Eq a, Show a, C a) => String -> SymbolicSpray a -> String
+ Math.Algebra.Hspray: prettySymbolicSprayX1X2X3 :: (Eq a, Show a, C a) => String -> String -> SymbolicSpray a -> String
+ Math.Algebra.Hspray: prettySymbolicSprayXYZ :: (Eq a, Show a, C a) => String -> [String] -> SymbolicSpray a -> String
+ Math.Algebra.Hspray: showNumSpray :: (Num a, Ord a) => ([Seq Int] -> [String]) -> (a -> String) -> Spray a -> String
+ Math.Algebra.Hspray: showQSpray :: ([Seq Int] -> [String]) -> QSpray -> String
+ Math.Algebra.Hspray: showQSpray' :: ([Seq Int] -> [String]) -> QSpray' -> String
+ Math.Algebra.Hspray: showSpray :: (a -> String) -> (String, String) -> ([Seq Int] -> [String]) -> Spray a -> String
+ Math.Algebra.Hspray: showSprayX1X2X3 :: (a -> String) -> (String, String) -> String -> Spray a -> String
+ Math.Algebra.Hspray: showSprayX1X2X3' :: (a -> String) -> String -> Spray a -> String
+ Math.Algebra.Hspray: showSprayXYZ :: (a -> String) -> (String, String) -> [String] -> Spray a -> String
+ Math.Algebra.Hspray: showSprayXYZ' :: (a -> String) -> [String] -> Spray a -> String
+ Math.Algebra.Hspray: type QSpray' = Spray Rational'
- Math.Algebra.Hspray: prettySpray :: (a -> String) -> String -> Spray a -> String
+ Math.Algebra.Hspray: prettySpray :: Show a => Spray a -> String
- Math.Algebra.Hspray: prettySpray'' :: (a -> String) -> Spray a -> String
+ Math.Algebra.Hspray: prettySpray'' :: Show a => String -> Spray a -> String
- Math.Algebra.Hspray: prettySprayXYZ :: Show a => Spray a -> String
+ Math.Algebra.Hspray: prettySprayXYZ :: Show a => [String] -> Spray a -> String
- Math.Algebra.Hspray: type QSpray = Spray Rational'
+ Math.Algebra.Hspray: type QSpray = Spray Rational

Files

CHANGELOG.md view
@@ -101,8 +101,27 @@ 
 * New function `psPolynomial` which computes the power sum polynomials.
 
-* A particular type of sprays, namely `SymbolicSpray a`, has been introduced. The coefficients of these 
-sprays are ratios of univariate polynomials with `a` coefficients. There is a specialization 
+* A particular type of sprays, namely `SymbolicSpray a`, has been introduced. The coefficients of 
+these sprays are ratios of univariate polynomials with `a` coefficients. There is a specialization 
 `SymbolicQSpray` for the case when `a` is a type of rational numbers. The necessary instances have 
-been defined and there is the function `prettySymbolic(Q)Spray` to display such sprays. There are also 
-some functions to perform evaluation of such sprays.+been defined and there is the function `prettySymbolic(Q)Spray` to display such sprays. There are 
+also some functions to perform evaluation of such sprays.
+
+
+## 0.2.6.0 - 2024-04-15
+
+* New function `collinearSprays` which checks whether two sprays are collinear.
+
+* The function `isPolynomialOf` threw an error when the number of variables in the spray 
+to be tested was less than the number of variables in the list of sprays. That is me who 
+programmed this error and this was wrong: for example, `x = p1 - p2^*^p3` with `p1 = x + y^*^z`, 
+`p2 = y`, and `p3 = z`.
+
+* New functions to print sprays with numeric coefficients, such as `prettyNumSpray` and 
+`prettyQSpray`.
+
+* The functions `prettySpray`, `prettySpray'` and `prettySpray''` have been changed.
+
+* New functions to print symbolic sprays.
+
+* Documentation and README have been improved.
README.md view
@@ -9,6 +9,8 @@ 
 ___
 
+The `Spray a` type represents the multivariate polynomials with coefficients 
+in `a`. For example:
 
 ```haskell
 import Math.Algebra.Hspray
@@ -16,10 +18,32 @@ y = lone 2 :: Spray Double
 z = lone 3 :: Spray Double
 poly = (2 *^ (x^**^3 ^*^ y ^*^ z) ^+^ x^**^2) ^*^ (4 *^ (x ^*^ y ^*^ z))
-prettySpray show "X" poly
--- "(4.0) * X^(3, 1, 1) + (8.0) * X^(4, 2, 2)"
+putStrLn $ prettyNumSpray poly
+-- 8.0*x^4.y^2.z^2 + 4.0*x^3.y.z
 ```
 
+This is the easiest way to construct a spray: first introduce the polynomial 
+variables with the `lone` function, and then use arithmetic operations.
+
+There are numerous functions to print a spray. If you don't like the letters 
+`x`, `y`, `z` in the output of `prettyNumSpray`, you can use `prettyNumSprayXYZ` 
+to change them to whatever you want:
+
+```haskell
+putStrLn $ prettyNumSprayXYZ ["A","B","C"] poly
+-- 8.0*A^4.B^2.C^2 + 4.0*A^3.B.C
+```
+
+Note that this function does not throw an error if you don't provide enough 
+letters:
+
+```haskell
+putStrLn $ prettyNumSprayXYZ ["A","B"] poly
+-- 8.0*A1^4.A2^2.A3^2 + 4.0*A1^3.A2.A3
+```
+
+This is the same output as the one of `prettyNumSprayX1X2X3 "A" poly`.
+
 More generally, one can use the type `Spray a` as long as the type `a` has 
 the instances `Eq` and `Algebra.Ring` (defined in the **numeric-prelude** 
 library). For example `a = Rational`:
@@ -27,24 +51,24 @@ ```haskell
 import Math.Algebra.Hspray
 import Data.Ratio
-x = lone 1 :: Spray Rational
-y = lone 2 :: Spray Rational
-z = lone 3 :: Spray Rational
-poly = ((2%3) *^ (x^**^3 ^*^ y ^*^ z) ^+^ x^**^2) ^*^ ((7%4) *^ (x ^*^ y ^*^ z))
-prettySpray show "X" poly
--- "(7 % 4) * X^(3, 1, 1) + (7 % 6) * X^(4, 2, 2)"
+x = lone 1 :: QSpray -- QSpray = Spray Rational
+y = lone 2 :: QSpray 
+z = lone 3 :: QSpray
+poly = ((2%3) *^ (x^**^3 ^*^ y ^*^ z) ^-^ x^**^2) ^*^ ((7%4) *^ (x ^*^ y ^*^ z))
+putStrLn $ prettyQSpray poly
+-- (7/6)*x^4.y^2.z^2 - (7/4)*x^3.y.z
 ```
 
 Or `a = Spray Double`:
 
 ```haskell
 import Math.Algebra.Hspray
-p = lone 1 :: Spray Double
+alpha = lone 1 :: Spray Double
 x = lone 1 :: Spray (Spray Double)
 y = lone 2 :: Spray (Spray Double)
-poly = ((p *^ x) ^+^ (p *^ y))^**^2  
-prettySpray (prettySpray show "a") "X" poly
--- "((1.0) * a^(2)) * X^(0, 2) + ((2.0) * a^(2)) * X^(1, 1) + ((1.0) * a^(2)) * X^(2)"
+poly = ((alpha *^ x) ^+^ (alpha *^ y))^**^2  
+showSprayXYZ' (prettyNumSprayXYZ ["alpha"]) ["x","y"] poly
+-- (alpha^2)*x^2 + (2.0*alpha^2)*x.y + (alpha^2)*y^2
 ```
 
 #### Evaluation:
@@ -69,13 +93,13 @@ x2 = lone 2 :: Spray Rational
 x3 = lone 3 :: Spray Rational
 poly = x1^**^2 ^+^ x2 ^+^ x3 ^-^ unitSpray
-prettySpray' poly
--- "((-1) % 1) + (1 % 1) x3 + (1 % 1) x2 + (1 % 1) x1^2"
+putStrLn $ prettyQSprayX1X2X3 "x" poly
+-- x1^2 + x2 + x3 - 1
 --
 -- substitute x1 -> 2 and x3 -> 3
-poly' = substituteSpray [Just 2, Nothing, Just 3] p
-prettySpray' poly'
--- "(6 % 1) + (1 % 1) x2"
+poly' = substituteSpray [Just 2, Nothing, Just 3] poly
+putStrLn $ prettyQSprayX1X2X3 "x" poly'
+-- x2 + 6
 ```
 
 #### Differentiation:
@@ -86,9 +110,12 @@ y = lone 2 :: Spray Double
 z = lone 3 :: Spray Double
 poly = 2 *^ (x ^*^ y ^*^ z) ^+^ (3 *^ x^**^2)
--- derivate with respect to x
-prettySpray show "X" $ derivSpray 1 poly
--- "(2.0) * X^(0, 1, 1) + (6.0) * X^(1)"
+putStrLn $ prettyNumSpray poly
+-- 3.0*x^2 + 2.0*x.y.z
+--
+-- derivative with respect to x
+putStrLn $ prettyNumSpray $ derivSpray 1 poly
+-- 6.0*x + 2.0*y.z"
 ```
 
 ## Gröbner bases
@@ -99,7 +126,7 @@ import Math.Algebra.Hspray
 import Data.Ratio
 -- define the elementary monomials
-o = lone 0 :: Spray Rational
+o = lone 0 :: Spray Rational -- same as unitSpray
 x = lone 1 :: Spray Rational
 y = lone 2 :: Spray Rational
 z = lone 3 :: Spray Rational
@@ -110,12 +137,12 @@ -- compute the reduced Gröbner basis
 gbasis = groebner [p1, p2, p3] True
 -- show result
-prettyResult = map prettySprayXYZ gbasis
+prettyResult = map prettyQSpray gbasis
 mapM_ print prettyResult
--- "((-1) % 1) + (1 % 1) Z^2 + (1 % 1) Y + (1 % 1) X"
--- "(1 % 1) Z + ((-1) % 1) Z^2 + ((-1) % 1) Y + (1 % 1) Y^2"
--- "((-1) % 2) Z^2 + (1 % 2) Z^4 + (1 % 1) YZ^2"
--- "((-1) % 1) Z^2 + (4 % 1) Z^3 + ((-4) % 1) Z^4 + (1 % 1) Z^6"
+-- "x + y + z^2 - 1"
+-- "y^2 - y - z^2 + z"
+-- "y.z^2 + (1/2)*z^4 - (1/2)*z^2"
+-- "z^6 - 4*z^4 + 4*z^3 - z^2"
 ```
 
 
@@ -138,6 +165,7 @@ [Hackage page](https://hackage.haskell.org/package/numeric-prelude-0.4.4#usage) 
 of **numeric-prelude**.
 
+
 ## Symbolic coefficients
 
 Assume you have the polynomial `a * (x² + y²) + 2b/3 * z`, 
@@ -160,11 +188,10 @@ b = lone 2 :: Spray Rational
 
 poly = a *^ (x*x + y*y) + ((2%3) *^ b) *^ z 
-prettySpray (prettySpray show "a") "X" poly
--- "((2 % 3) * a^(0, 1)) * X^(0, 0, 1) + ((1 % 1) * a^(1)) * X^(0, 2) + ((1 % 1) * a^(1)) * X^(2)"
+putStrLn $ showSprayXYZ' (prettyQSprayXYZ ["a","b"]) ["X","Y","Z"] poly
+-- (a)*X^2 + (a)*Y^2 + ((2/3)*b)*Z
 ```
 
-The `prettySpray` function shows the expansion of the polynomial. 
 You can extract the powers and the coefficients as follows:
 
 ```haskell
@@ -179,8 +206,13 @@ 
 If you have only one symbolic coefficient, it is easier to deal with the sprays of type 
 `SymbolicSpray`. These are sprays whose coefficients are ratios of univariate polynomials, 
-so this allows more possibilities than a `Spray (Spray a)`. 
-Assume you want to deal with the polynomial `4/5 * a/(a² + a + 1) * (x² + y²) + 2a/3 * yz`. 
+so this allows more possibilities than a `Spray (Spray a)`. Since the variable 
+of these univariate polynomials occurs in the coefficients of such a spray, I 
+call it the *outer variable* sometimes, although I do not very like this name 
+(see below). And I say that the variables of the symbolic spray are the 
+*inner variables* or the *main variables*, though I would prefer to simply call 
+them the *variables*.
+Assume you want to deal with the polynomial `4/5 * a/(a² + 1) * (x² + y²) + 2a/3 * yz`. 
 Then you define it as follows:
 
 ```haskell
@@ -197,44 +229,58 @@ z = lone 3 :: SymbolicQSpray 
 a = outerQVariable  
 sSpray 
-  = ((4%5) *. (a :% (a^2 + a + one))) *> (x^2 + y^2)  +  (constQPoly (2%3) * a) *> (y * z)
-putStrLn $ prettySymbolicQSpray "a" sSpray
--- ([(4/5)a] / [(1) + a + a^2])*x1^2 + ([(4/5)a] / [(1) + a + a^2])*x2^2 + ((2/3)a)*x2x3
+  = ((4%5) *. (a :% (a^2 + one))) *> (x^2 + y^2)  +  (constQPoly (2%3) * a) *> (y * z)
+putStrLn $ prettySymbolicQSpray' "a" sSpray
+-- { [ (4/5)*a ] %//% [ a^2 + 1 ] }*X^2 + { [ (4/5)*a ] %//% [ a^2 + 1 ] }*Y^2 + { (2/3)*a }*Y.Z
 ```
 
-This pretty form of the symbolic qspray will be improved in a future version.
-
-There are three possible evaluations of this symbolic spray:
+There are three possible evaluations of a symbolic spray:
 
 ```haskell
 -- substitute a value for 'a':
-putStrLn $ prettySpray' $ evalSymbolicSpray sSpray (6%5)
--- (24 % 91) x1^2 + (24 % 91) x2^2 + (4 % 5) x2x3
+putStrLn $ 
+  prettyQSpray''' $ evalSymbolicSpray sSpray (6%5)
+-- (24/61)*X^2 + (24/61)*Y^2 + (4/5)*Y.Z
 
--- substitue a value for 'a' and some values for 'x1', 'x2', 'x3':
+-- substitute a value for 'a' and some values for 'X', 'Y', 'Z':
 evalSymbolicSpray' sSpray (6%5) [2, 3, 4%7]
--- 24 % 5
+-- 13848 % 2135
 
--- substitue some values for 'x1', 'x2', 'x3':
+-- substitute some values for 'X', 'Y', 'Z':
 putStrLn $ 
   prettyRatioOfQPolynomials "a" $ evalSymbolicSpray'' sSpray [2, 3, 4%7]
--- [(404/35)a + (8/7)a^2 + (8/7)a^3] / [(1) + a + a^2]
+-- [ (8/7)*a^3 + (404/35)*a ] %//% [ a^2 + 1 ]
 ```
 
-The nice point regarding these ratios of univariate polynomials is that they are automatically 
-"simplified". For example:
+Although it does not make sense to replace the main variables (`X`, `Y`, `Z`)
+of a symbolic spray with some fractions of univariate polynomials, this feature 
+is not provided. We rather consider that a `SymbolicSpray K` spray defines a 
+multivariate polynomial on the field `K` whose coefficients lie in `K` but 
+depend on a parameter, the so-called outer variable (`"a"`). By the way I am not 
+a fan of this name, and maybe the *parameter* would be a better name? And then
+*parametric spray* would be a better name than *symbolic spray*? Do not 
+hesitate to open a Github issue to leave some comments if you want! 
 
+The nice point regarding these ratios of univariate polynomials is that they 
+are automatically "simplified" (i.e. written as irreducible fractions). 
+For example:
+
 ```haskell
-polyFrac = (a^8 - one) :% (a - one)
+polyFrac = (a^8 - one) ^/^ (a - one)
 putStrLn $ prettyRatioOfQPolynomials "a" polyFrac
--- (1) + a + a^2 + a^3 + a^4 + a^5 + a^6 + a^7
+-- a^7 + a^6 + a^5 + a^4 + a^3 + a^2 + a + 1
 ```
 
 Maybe you prefer the fractional form, but it is nice to see that this ratio of 
-polynomials actually is a polynomial.
+polynomials actually is a polynomial. 
+Note that I used `^/^` here and not `:%`. That's because `:%` does not simplify 
+the fraction, it just constructs a fraction with the given numerator and denominator.
+Whenever an arithmetic operation is performed on a fraction, the result is always 
+simplified. So the `^/^` operator simply constructs a fraction with `:%` and then 
+it multiplies it by one to get the simplification.
 
 
 ## Other features
 
-Resultant and subresultants of two polynomials, and greatest common divisor of two polynomials
-with coefficients in a field.+Resultant and subresultants of two polynomials, and greatest common divisor of 
+two polynomials with coefficients in a field.
hspray.cabal view
@@ -1,5 +1,5 @@ name:                hspray
-version:             0.2.5.0
+version:             0.2.6.0
 synopsis:            Multivariate polynomials.
 description:         Manipulation of multivariate polynomials on a commutative ring, Gröbner basis, resultant and subresultants, and greatest common divisor.
 homepage:            https://github.com/stla/hspray#readme
@@ -53,6 +53,15 @@                       , numeric-prelude >= 0.4.4 && < 0.5
                       , hspray
   Default-Language:     Haskell2010
+  ghc-options:         -Wall
+                       -Wcompat
+                       -Widentities
+                       -Wincomplete-record-updates
+                       -Wincomplete-uni-patterns
+                       -Wmissing-export-lists
+                       -Wmissing-home-modules
+                       -Wpartial-fields
+                       -Wredundant-constraints
 
 benchmark benchmarks
   type:                 exitcode-stdio-1.0
src/Math/Algebra/Hspray.hs view
@@ -18,10 +18,11 @@ 
 module Math.Algebra.Hspray
   ( 
-  -- * Types
+  -- * Main types
     Powers (..)
   , Spray
   , QSpray
+  , QSpray'
   , Monomial
   -- * Basic sprays
   , lone
@@ -40,7 +41,28 @@   , prettySpray'
   , prettySpray''
   , prettySprayXYZ
-  -- * Univariate polynomials 
+  , prettySprayX1X2X3
+  , showSpray
+  , showSprayXYZ
+  , showSprayXYZ'
+  , showSprayX1X2X3
+  , showSprayX1X2X3'
+  , showNumSpray
+  , showQSpray
+  , showQSpray'
+  , prettyNumSprayX1X2X3
+  , prettyQSprayX1X2X3
+  , prettyQSprayX1X2X3'
+  , prettyNumSprayXYZ
+  , prettyQSprayXYZ
+  , prettyQSprayXYZ'
+  , prettyNumSpray
+  , prettyNumSpray'
+  , prettyQSpray
+  , prettyQSpray''
+  , prettyQSpray'
+  , prettyQSpray'''
+  -- * Univariate polynomials and fractions of univariate polynomials
   , A (..)
   , Rational'
   , Q
@@ -49,6 +71,7 @@   , RatioOfPolynomials
   , QPolynomial 
   , RatioOfQPolynomials
+  , (^/^)
   , prettyRatioOfPolynomials
   , prettyRatioOfQPolynomials
   , (*.)
@@ -59,11 +82,17 @@   , qpolyFromCoeffs
   , outerQVariable
   , evalRatioOfPolynomials
-  -- * Symbolic sprays (with univariate polynomials coefficients)
+  -- * Symbolic sprays 
   , SymbolicSpray
   , SymbolicQSpray
+  , prettySymbolicSprayX1X2X3
+  , prettySymbolicSprayXYZ
   , prettySymbolicSpray
+  , prettySymbolicSpray'
+  , prettySymbolicQSprayX1X2X3
+  , prettySymbolicQSprayXYZ
   , prettySymbolicQSpray
+  , prettySymbolicQSpray'
   , simplifySymbolicSpray
   , evalSymbolicSpray
   , evalSymbolicSpray'
@@ -71,6 +100,7 @@   -- * Queries on a spray
   , getCoefficient
   , getConstantTerm
+  , numberOfVariables
   , sprayTerms
   -- * Evaluation of a spray
   , evalSpray
@@ -106,6 +136,7 @@   , leadingTerm
   , isPolynomialOf
   , bombieriSpray
+  , collinearSprays
   ) where
 import qualified Algebra.Additive              as AlgAdd
 import qualified Algebra.Field                 as AlgField
@@ -125,6 +156,7 @@                                                 , elemIndices
                                                 , nub
                                                 , foldl1'
+                                                , uncons
                                                 )
 import           Data.Matrix                    ( Matrix 
                                                 , fromLists
@@ -137,6 +169,7 @@                                                 , fromJust, fromMaybe
                                                 )
 import           Data.Ord                       ( comparing )
+import qualified Data.Ratio                    as DR
 import qualified Data.Sequence                 as S
 import           Data.Sequence                  ( (><)
                                                 , Seq 
@@ -155,6 +188,7 @@                                                 , unpack
                                                 )
 import qualified MathObj.Polynomial            as MathPol
+import           Number.Ratio                   ( T ( (:%) ) )
 import qualified Number.Ratio                  as NumberRatio
 -- import qualified Algebra.PrincipalIdealDomain  as AlgPID
 -- import qualified Algebra.Units  as AlgUnits
@@ -179,6 +213,12 @@ type QPolynomial          = Polynomial Rational'
 type RatioOfQPolynomials  = RatioOfPolynomials Rational'
 
+-- | Division of univariate polynomials; this is an application of `:%` 
+-- followed by a simplification of the obtained fraction of the two polynomials
+(^/^) :: (Eq a, AlgField.C a) 
+      => Polynomial a -> Polynomial a -> RatioOfPolynomials a
+(^/^) pol1 pol2 = simplifyRatioOfPolynomials $ pol1 :% pol2 
+
 instance (Eq a, AlgField.C a) => AlgZT.C (A a) where
   isZero :: A a -> Bool
   isZero (A r) = r == AlgAdd.zero
@@ -208,8 +248,8 @@ polyFromCoeffs :: [a] -> Polynomial a
 polyFromCoeffs as = MathPol.fromCoeffs (map A as)
 
--- | The variable of a univariate polynomial; it is called \"outer\" because this is the variable 
--- occuring in the polynomial coefficients of a `SymbolicSpray` 
+-- | The variable of a univariate polynomial; it is called \"outer\" because 
+-- this is the variable occuring in the polynomial coefficients of a `SymbolicSpray` 
 outerVariable :: AlgRing.C a => Polynomial a
 outerVariable = polyFromCoeffs [AlgAdd.zero, AlgRing.one] 
 
@@ -217,6 +257,8 @@ -- 
 -- >>> import Number.Ratio ( (%) )
 -- >>> constQPoly (2 % 3)
+--
+-- prop> constQPoly (2 % 3) == qpolyFromCoeffs [2 % 3]
 constQPoly :: Rational' -> QPolynomial
 constQPoly = constPoly
 
@@ -227,14 +269,16 @@ qpolyFromCoeffs :: [Rational'] -> QPolynomial
 qpolyFromCoeffs = polyFromCoeffs
 
--- | The variable of a univariate qpolynomial; it is called \"outer\" because this is the variable 
--- occuring in the polynomial coefficients of a `SymbolicQSpray` 
+-- | The variable of a univariate rational polynomial; it is called \"outer\" 
+-- because it is the variable occuring in the coefficients of a `SymbolicQSpray` 
+-- (but I do not like this name - see README) 
 --
 -- prop> outerQVariable == qpolyFromCoeffs [0, 1] 
 outerQVariable :: QPolynomial
 outerQVariable = qpolyFromCoeffs [0, 1] 
 
--- show a ratio
+{- 
+-- show a ratio, helper function
 showQ :: (Eq a, Num a, Show a) => NumberRatio.T a -> String
 showQ q = if d == 1 
   then show n 
@@ -242,20 +286,60 @@   where
     n = NumberRatio.numerator q
     d = NumberRatio.denominator q 
+ -}
 
+-- | identify a `Polynomial a` to a `Spray a`, in order to apply the show spray 
+-- functions to the univariate polynomials
+polynomialToSpray :: forall a. (Eq a, AlgRing.C a) => Polynomial a -> Spray a
+polynomialToSpray pol = AlgAdd.sum terms
+  where
+    coeffs   = MathPol.coeffs pol
+    indices = findIndices (/= A AlgAdd.zero) coeffs
+    get :: A a -> a
+    get (A x) = x
+    terms = map (\i -> get (coeffs!!i) *^ (lone 1 ^**^ i)) indices
+
+-- helper function; it encloses a string between two given delimiters
+bracify :: (String, String) -> String -> String
+bracify (lbrace, rbrace) x = lbrace ++ x ++ rbrace 
+
 -- | helper function for prettyRatioOfPolynomials (and prettySymbolicSpray)
+showRatioOfPolynomials :: forall a. (Eq a, AlgField.C a) 
+                  => (Spray a -> String) -> RatioOfPolynomials a -> String
+showRatioOfPolynomials sprayShower polysRatio = 
+  numeratorString ++ denominatorString
+  where
+    numerator         = NumberRatio.numerator polysRatio
+    denominator       = NumberRatio.denominator polysRatio
+    brackets          = denominator /= MathPol.const (A AlgRing.one)
+    enclose = bracify ("[ ", " ]")
+    numeratorString   = if brackets
+      then enclose (sprayShower (polynomialToSpray numerator))
+      else sprayShower (polynomialToSpray numerator)
+    denominatorString = if not brackets
+      then ""
+      else " %//% " ++ enclose (sprayShower (polynomialToSpray denominator))
+
+-- | Pretty form of a ratio of univariate polynomials with rational coefficients
+prettyRatioOfQPolynomials
+  :: String               -- ^ a string to denote the variable, e.g. @"a"@ 
+  -> RatioOfQPolynomials 
+  -> String 
+prettyRatioOfQPolynomials var = showRatioOfPolynomials (prettyQSprayXYZ' [var])
+
+-- | helper function for prettyRatioOfPolynomials (and prettySymbolicSpray)
 showQpol :: forall a. (Eq a, AlgField.C a) 
          => Polynomial a -> String -> (a -> String) -> Bool -> String
 showQpol pol variable showCoeff brackets = if brackets 
-  then '[' : polyString ++ "]"
+  then "[ " ++ polyString ++ " ]"
   else polyString
   where
     showCoeff' :: Int -> A a -> String
     showCoeff' i (A coeff) = case i of 
-      0 -> '(' : showCoeff coeff ++ ")"
+      0 -> (bracify ("(", ")") . showCoeff) coeff
       _ -> if coeff == AlgRing.one 
         then "" 
-        else '(' : showCoeff coeff ++ ")"
+        else (bracify ("(", ")") . showCoeff) coeff
     coeffs   = MathPol.coeffs pol
     nonzeros = findIndices (/= A AlgAdd.zero) coeffs
     terms    = map (pack . showTerm) nonzeros
@@ -273,24 +357,26 @@   where
     denominator       = NumberRatio.denominator polysRatio
     brackets          = denominator /= MathPol.const (A AlgRing.one)
-    numeratorString   = showQpol (NumberRatio.numerator polysRatio) var showCoeff brackets
+    numeratorString   = 
+      showQpol (NumberRatio.numerator polysRatio) var showCoeff brackets
     denominatorString = if not brackets
       then ""
-      else " / " ++ showQpol denominator var showCoeff True
+      else " %//% " ++ showQpol denominator var showCoeff True
 
 -- | Pretty form of a ratio of univariate polynomials
 prettyRatioOfPolynomials :: (Eq a, AlgField.C a, Show a) 
-  => String               -- ^ a string to denote the variable, e.g. @"a"@
+  => String               -- ^ string (usually a single letter) to denote the variable, e.g. @"a"@
   -> RatioOfPolynomials a 
   -> String 
 prettyRatioOfPolynomials var = showQpolysRatio var show 
 
--- | Pretty form of a ratio of univariate qpolynomials
-prettyRatioOfQPolynomials 
+{- -- | Pretty form of a ratio of univariate qpolynomials
+prettyRatioOfQPolynomials' 
   :: String               -- ^ a string to denote the variable, e.g. @"a"@ 
   -> RatioOfQPolynomials 
   -> String 
-prettyRatioOfQPolynomials var = showQpolysRatio var showQ
+prettyRatioOfQPolynomials' var = showQpolysRatio var showQ
+ -}
 
 -- | Evaluates a ratio of univariate polynomials
 evalRatioOfPolynomials :: AlgField.C a 
@@ -300,8 +386,10 @@ evalRatioOfPolynomials value polysRatio = 
   resultNumerator AlgField./ resultDenominator
   where
-    A resultNumerator   = MathPol.evaluate (NumberRatio.numerator polysRatio) (A value)
-    A resultDenominator = MathPol.evaluate (NumberRatio.denominator polysRatio) (A value)
+    A resultNumerator   = 
+      MathPol.evaluate (NumberRatio.numerator polysRatio) (A value)
+    A resultDenominator = 
+      MathPol.evaluate (NumberRatio.denominator polysRatio) (A value)
 
 
 -- Symbolic sprays ------------------------------------------------------------
@@ -309,28 +397,107 @@ type SymbolicSpray a = Spray (RatioOfPolynomials a)
 type SymbolicQSpray  = SymbolicSpray Rational'
 
--- | Simplifies the coefficients (the ratio of univariate polynomials) of a 
+-- | simplifies a ratio of polynomials (simply by multiplying it by one)
+simplifyRatioOfPolynomials :: 
+  (Eq a, AlgField.C a) => RatioOfPolynomials a -> RatioOfPolynomials a
+simplifyRatioOfPolynomials = (AlgRing.*) AlgRing.one
+
+-- | Simplifies the coefficients (the fractions of univariate polynomials) of a 
 -- symbolic spray
 simplifySymbolicSpray :: 
   (Eq a, AlgField.C a) => SymbolicSpray a -> SymbolicSpray a
-simplifySymbolicSpray = HM.map (AlgAdd.+ AlgAdd.zero)
+simplifySymbolicSpray = HM.map simplifyRatioOfPolynomials
 
--- | Pretty form of a symbolic spray
-prettySymbolicSpray 
+-- | Pretty form of a symbolic spray, using a string (typically a letter) 
+-- followed by an index to denote the variables
+prettySymbolicSprayX1X2X3 
   :: (Eq a, Show a, AlgField.C a) 
-  => String          -- ^ a string to denote the outer variable of the spray, e.g. @"a"@
+  => String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> String          -- ^ typically a letter, to denote the non-indexed variables
   -> SymbolicSpray a -- ^ a symbolic spray; note that this function does not simplify it
   -> String 
-prettySymbolicSpray var = prettySpray'' (showQpolysRatio var show)
+prettySymbolicSprayX1X2X3 a = showSprayX1X2X3 (prettyRatioOfPolynomials a) ("{ ", " }")
 
--- | Pretty form of a symbolic qspray
-prettySymbolicQSpray 
-  :: String          -- ^ a string to denote the outer variable of the spray, e.g. @"a"@
+-- | Pretty form of a symbolic spray, using some given strings (typically some 
+-- letters) to denote the variables if possible, i.e. if enough letters are 
+-- provided; otherwise this function behaves exactly like 
+-- @prettySymbolicQSprayX1X2X3 a@ where @a@ is the first provided letter
+prettySymbolicSprayXYZ 
+  :: (Eq a, Show a, AlgField.C a) 
+  => String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> [String]        -- ^ typically some letters, to denote the main variables
+  -> SymbolicSpray a -- ^ a symbolic spray; note that this function does not simplify it
+  -> String 
+prettySymbolicSprayXYZ a = showSprayXYZ (prettyRatioOfPolynomials a) ("{ ", " }")
+
+-- | Pretty form of a symbolic spray; see the definition below and see
+-- `prettySymbolicSprayXYZ`
+--
+-- prop> prettySymbolicSpray a spray == prettySymbolicSprayXYZ a ["x","y","z"] spray
+prettySymbolicSpray
+  :: (Eq a, Show a, AlgField.C a) 
+  => String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> SymbolicSpray a -- ^ a symbolic spray; note that this function does not simplify it
+  -> String 
+prettySymbolicSpray a = prettySymbolicSprayXYZ a ["x", "y", "z"]
+
+-- | Pretty form of a symbolic spray; see the definition below and see
+-- `prettySymbolicSprayXYZ`
+--
+-- prop> prettySymbolicSpray' a spray == prettySymbolicSprayXYZ a ["X","Y","Z"] spray
+prettySymbolicSpray'
+  :: (Eq a, Show a, AlgField.C a) 
+  => String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> SymbolicSpray a -- ^ a symbolic spray; note that this function does not simplify it
+  -> String 
+prettySymbolicSpray' a = prettySymbolicSprayXYZ a ["X", "Y", "Z"]
+
+-- | Pretty form of a symbolic rational spray, using a string (typically a letter) 
+-- followed by an index to denote the variables
+prettySymbolicQSprayX1X2X3 
+  :: String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> String          -- ^ string to denote the non-indexed variables of the spray
   -> SymbolicQSpray  -- ^ a symbolic qspray; note that this function does not simplify it
   -> String 
-prettySymbolicQSpray var = prettySpray'' (showQpolysRatio var showQ)
+prettySymbolicQSprayX1X2X3 a x = 
+  showSpray (prettyRatioOfQPolynomials a) ("{ ", " }") (showMonomialsX1X2X3 x)
 
--- | Substitutes a value to the outer variable of a symbolic spray
+-- | Pretty form of a symbolic rational spray, using some given strings (typically some 
+-- letters) to denote the variables if possible, i.e. if enough letters are 
+-- provided; otherwise this function behaves exactly like 
+-- @prettySymbolicQSprayX1X2X3 a@ where @a@ is the first provided letter
+prettySymbolicQSprayXYZ 
+  :: String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> [String]        -- ^ usually some letters, to denote the variables of the spray
+  -> SymbolicQSpray  -- ^ a symbolic qspray; note that this function does not simplify it
+  -> String 
+prettySymbolicQSprayXYZ a letters = 
+  showSpray (prettyRatioOfQPolynomials a) ("{ ", " }") (showMonomialsXYZ letters)
+
+-- | Pretty form of a symbolic rational spray, using @"x"@, @"y"@ and @"z"@ for the variables 
+-- if possible; i.e. if the spray does not have more than three variables, otherwise 
+-- @"x1"@, @"x2"@, ... are used to denote the variables
+--
+-- prop> prettySymbolicQSpray a == prettySymbolicQSprayXYZ a ["x","y","z"]
+prettySymbolicQSpray 
+  :: String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> SymbolicQSpray  -- ^ the symbolic qspray to be printed; note that this function does not simplify it
+  -> String 
+prettySymbolicQSpray a = prettySymbolicQSprayXYZ a ["x", "y", "z"] 
+
+-- | Pretty form of a symbolic rational spray, using @"X"@, @"Y"@ and @"Z"@ for the variables 
+-- if possible; i.e. if the spray does not have more than three variables, otherwise 
+-- @"X1"@, @"X2"@, ... are used 
+--
+-- prop> prettySymbolicQSpray' a = prettySymbolicQSprayXYZ a ["X","Y","Z"]
+prettySymbolicQSpray' 
+  :: String          -- ^ string to denote the outer variable of the spray, e.g. @"a"@
+  -> SymbolicQSpray  -- ^ the symbolic qsprayto be printed; note that this function does not simplify it
+  -> String 
+prettySymbolicQSpray' a = prettySymbolicQSprayXYZ a ["X", "Y", "Z"] 
+
+-- | Substitutes a value to the outer variable of a symbolic spray 
+-- (the variable occuring in the coefficients)
 evalSymbolicSpray :: AlgField.C a => SymbolicSpray a -> a -> Spray a
 evalSymbolicSpray spray x = HM.map (evalRatioOfPolynomials x) spray 
 
@@ -345,7 +512,7 @@   then evalSpray (evalSymbolicSpray spray x) xs
   else error "evalSymbolicSpray': not enough values provided."
 
--- helper function for evalSymbolicSpray''
+-- | helper function for evalSymbolicSpray''
 evalSymbolicMonomial :: (Eq a, AlgField.C a) 
   => [a] -> Monomial (RatioOfPolynomials a) -> RatioOfPolynomials a
 evalSymbolicMonomial xs (powers, coeff) = 
@@ -406,7 +573,8 @@ 
 type Monomial a = (Powers, a)
 type Spray a = HashMap Powers a
-type QSpray = Spray Rational'
+type QSpray = Spray Rational
+type QSpray' = Spray Rational'
 
 -- | addition of two sprays
 addSprays :: (AlgAdd.C a, Eq a) => Spray a -> Spray a -> Spray a
@@ -484,11 +652,12 @@ -- | Power of a spray
 (^**^) :: (AlgRing.C a, Eq a) => Spray a -> Int -> Spray a
 (^**^) p n = if n >= 0 
-  then AlgRing.product (replicate n p)
+  then p AlgRing.^ fromIntegral n
   else error "(^**^): negative power of a spray is not allowed."
 
 infixr 7 *^
--- | Scale a spray by a scalar
+-- | Scale a spray by a scalar; if you import the /Algebra.Module/ module 
+-- then it is the same operation as @(*>)@ from this module
 (*^) :: (AlgRing.C a, Eq a) => a -> Spray a -> Spray a
 (*^) lambda pol = lambda AlgMod.*> pol
 
@@ -523,6 +692,13 @@     pows'  = Powers expts' (nvariables pows) 
 
 -- | Derivative of a spray
+--
+-- >>> x :: lone 1 :: Spray Int
+-- >>> y :: lone 2 :: Spray Int
+-- >>> spray = 2*^x ^-^ 3*^y^**^8
+-- >>> spray' = derivSpray 1 spray
+-- >>> putStrLn $ prettyNumSpray spray'
+-- 2
 derivSpray 
   :: (AlgRing.C a, Eq a) 
   => Int     -- ^ index of the variable of differentiation (starting at 1)
@@ -535,13 +711,15 @@   p'        = HM.toList p
   monomials = [ derivMonomial i mp | mp <- p' ]
 
--- | Spray corresponding to the basic monomial x_n
+-- | The @n@-th polynomial variable @x_n@ as a spray; one usually builds a 
+-- spray by introducing these variables and combining them with the arithmetic 
+-- operations
 --
 -- >>> x :: lone 1 :: Spray Int
 -- >>> y :: lone 2 :: Spray Int
--- >>> p = 2*^x^**^2 ^-^ 3*^y
--- >>> putStrLn $ prettySpray' p
--- (2) x1^2 + (-3) x2
+-- >>> spray = 2*^x^**^2 ^-^ 3*^y
+-- >>> putStrLn $ prettyNumSpray spray
+-- 2*x^2 - 3*y
 --
 -- prop> lone 0 == unitSpray
 lone :: AlgRing.C a => Int -> Spray a
@@ -565,6 +743,10 @@ zeroSpray :: (Eq a, AlgAdd.C a) => Spray a
 zeroSpray = AlgAdd.zero
 
+-- | whether the spray is zero
+isZeroSpray :: Spray a -> Bool
+isZeroSpray spray = HM.size spray == 0
+
 -- | Constant spray
 --
 -- prop> constantSpray 3 == 3 *^ unitSpray
@@ -646,8 +828,8 @@ -- >>> x3 :: lone 3 :: Spray Int
 -- >>> p = x1^**^2 ^-^ x2 ^+^ x3 ^-^ unitSpray
 -- >>> p' = substituteSpray [Just 2, Nothing, Just 3] p
--- >>> putStrLn $ prettySpray' p'
--- (-1) x2 + (6) 
+-- >>> putStrLn $ prettyNumSpray p'
+-- -x2 + 6 
 substituteSpray :: (Eq a, AlgRing.C a) => [Maybe a] -> Spray a -> Spray a
 substituteSpray subs spray = if length subs == n 
   then spray'
@@ -671,8 +853,8 @@ -- >>> z :: lone 3 :: Spray Int
 -- >>> p = x ^+^ y
 -- >>> q = composeSpray p [z, x ^+^ y ^+^ z]
--- >>> putStrLn $ prettySprayXYZ q
--- (1) X + (1) Y + (2) Z
+-- >>> putStrLn $ prettyNumSpray' q
+-- X + Y + 2*Z
 composeSpray :: forall a. (AlgRing.C a, Eq a) 
                 => Spray a -> [Spray a] -> Spray a
 composeSpray p = evalSpray (identify p)
@@ -714,9 +896,9 @@     powers' = map (\exps -> simplifyPowers (Powers exps n')) expnts'
     spray'  = HM.fromList (zip powers' coeffs)
 
--- | Swaps two variables of a spray
+-- | Swaps two variables whithin a spray
 -- 
--- prop> swapVariables (1, 3) p == permuteVariables [3, 2, 1] p
+-- prop> swapVariables (1, 3) spray == permuteVariables [3, 2, 1] spray
 swapVariables :: (Int, Int) -> Spray a -> Spray a
 swapVariables (i, j) spray = 
   if i>=1 && j>=1  
@@ -739,128 +921,381 @@ 
 -- pretty stuff ---------------------------------------------------------------
 
--- | prettyPowers "x" [0, 2, 1] = x^(0, 2, 1)
-prettyPowers :: String -> [Int] -> Text
-prettyPowers var pows = append (pack x) (cons '(' $ snoc string ')')
- where
-  x      = " " ++ var ++ "^"
-  string = intercalate (pack ", ") (map (pack . show) pows)
+-- | Prints a spray; this function is exported for 
+-- possible usage in other packages
+showSpray 
+  :: (a -> String)           -- ^ function mapping a coefficient to a string, typically 'show'
+  -> (String, String)        -- ^ pair of braces to enclose the coefficients
+  -> ([Seq Int] -> [String]) -- ^ function mapping a list of exponents to a list of strings representing the monomials corresponding to these exponents
+  -> Spray a                 -- ^ the spray to be printed
+  -> String
+showSpray showCoef braces showMonomials spray = 
+  if isZeroSpray spray 
+    then "0"
+    else unpack $ intercalate (pack " + ") stringTerms
+  where
+    terms = sortBy (flip compare `on` fexpts) (HM.toList spray)
+    fexpts term = exponents $ fst term
+    coeffs = map snd terms
+    powers = map (exponents . fst) terms
+    stringMonomials = showMonomials powers
+    stringTerms = zipWith f coeffs stringMonomials
+    f coeff smonomial 
+      | smonomial == "" = pack scoeff'
+      | scoeff == ""    = pack smonomial
+      | otherwise       = pack $ scoeff' ++ "*" ++ smonomial
+      where
+        scoeff  = showCoef coeff
+        scoeff' = bracify braces scoeff 
 
--- | Pretty form of a spray
+-- | Prints a spray, with monomials shown as "x.z^2", and with 
+-- a user-defined showing function for the coefficients
+showSprayXYZ 
+  :: (a -> String)           -- ^ function mapping a coefficient to a string, typically 'show'
+  -> (String, String)        -- ^ used to enclose the coefficients, usually a pair of braces
+  -> [String]                -- ^ strings, typically some letters, to print the variables
+  -> Spray a                 -- ^ the spray to be printed
+  -> String
+showSprayXYZ showCoef braces letters spray =
+  if null letters
+    then error "showSprayXYZ: empty list of strings."
+    else showSpray showCoef braces (showMonomialsXYZ letters) spray
+
+-- | Prints a spray, with monomials shown as @"x.z^2"@, and with 
+-- a user-defined showing function for the coefficients; this is the same as 
+-- the function `showSprayXYZ` with the pair of braces @("(", ")")@
+showSprayXYZ' 
+  :: (a -> String)           -- ^ function mapping a coefficient to a string, typically 'show'
+  -> [String]                -- ^ strings, typically some letters, to print the variables
+  -> Spray a                 -- ^ the spray to be printed
+  -> String
+showSprayXYZ' showCoef = showSprayXYZ showCoef ("(", ")")
+
+-- | Pretty form of a spray with monomials displayed in the style of @"x.z^2"@; 
+-- you should rather use `prettyNumSprayXYZ` or `prettyQSprayXYZ` if your 
+-- coefficients are numeric
 --
--- >>> x :: lone 1 :: Spray Int
--- >>> y :: lone 2 :: Spray Int
--- >>> z :: lone 3 :: Spray Int
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
 -- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
--- >>> putStrLn $ prettySpray show "x" p
--- (2) * x^(1) + (3) * x^(0, 2) + (-4) * x^(0, 0, 3)
-prettySpray 
-  :: (a -> String) -- ^ function mapping a coefficient to a string, typically 'show'
-  -> String        -- ^ a string denoting the variable, e.g. \"x\"
-  -> Spray a       -- ^ the spray
+-- >>> putStrLn $ prettySprayXYZ ["X", "Y", "Z"] p
+-- (2)*X + (3)*Y^2 + (-4)*Z^3
+-- >>> putStrLn $ prettySprayXYZ ["X", "Y"] p
+-- (2)*X1 + (3)*X2^2 + (-4)*X3^3
+prettySprayXYZ :: (Show a) 
+  => [String]                -- ^ typically some letters, to print the variables
+  -> Spray a                 -- ^ the spray to be printed
   -> String
-prettySpray prettyCoef var p = unpack $ intercalate (pack " + ") stringTerms
- where
-  stringTerms     = 
-    map stringTerm (sortBy (flip compare `on` fexpts) (HM.toList p))
-  fexpts term     = exponents $ fst term
-  stringTerm term = append
-    (snoc (snoc (cons '(' $ snoc stringCoef ')') ' ') '*')
-    (prettyPowers var pows)
-   where
-    pows       = DF.toList $ exponents (fst term)
-    stringCoef = pack $ prettyCoef (snd term)
+prettySprayXYZ = showSprayXYZ' show
+  
+-- | Pretty form of a spray, with monomials shown as "x1.x3^2", and with 
+-- a user-defined showing function for the coefficients
+showSprayX1X2X3
+  :: (a -> String)           -- ^ function mapping a coefficient to a string, typically 'show'
+  -> (String, String)        -- ^ used to enclose the coefficients
+  -> String                  -- ^ typically a letter, to print the non-indexed variables
+  -> Spray a                 -- ^ the spray to be printed
+  -> String
+showSprayX1X2X3 showCoef braces letter =
+  showSpray showCoef braces (showMonomialsX1X2X3 letter)
 
--- | prettyPowers' [0, 2, 1] = "x2^2x3"
-prettyPowers' :: Seq Int -> Text
-prettyPowers' pows = pack x1x2x3
- where
-  n = S.length pows
-  f i p 
-    | p == 0    = ""
-    | p == 1    = "x" ++ show i
-    | otherwise = "x" ++ show i ++ "^" ++ show p
-  x1x2x3 = concatMap (\i -> f i (pows `index` (i-1))) [1 .. n]
+-- | Pretty form of a spray, with monomials shown as "x1.x3^2", and with 
+-- a user-defined showing function for the coefficients; this is the same as 
+-- the function `showSprayX1X2X3` with the pair of braces @("(", ")")@ used to 
+-- enclose the coefficients
+showSprayX1X2X3'
+  :: (a -> String)           -- ^ function mapping a coefficient to a string, e.g. 'show'
+  -> String                  -- ^ typically a letter, to print the non-indexed variables
+  -> Spray a                 -- ^ the spray to be printed
+  -> String
+showSprayX1X2X3' showCoef = showSprayX1X2X3 showCoef ("(", ")")
 
--- | Pretty form of a spray, with monomials shown as "x1x3^2"
+-- | Pretty form of a spray with monomials displayed in the style of @"x1.x3^2"@; 
+-- you should rather use `prettyNumSprayX1X2X3` or `prettyQSprayX1X2X3` if your 
+-- coefficients are numeric
 --
--- >>> x :: lone 1 :: Spray Int
--- >>> y :: lone 2 :: Spray Int
--- >>> z :: lone 3 :: Spray Int
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
+-- >>> spray = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
+-- >>> putStrLn $ prettySprayX1X2X3 "X" spray
+-- (2)*X1 + (3)*X2^2 + (-4)*X3^3
+prettySprayX1X2X3 :: (Show a) 
+  => String                -- ^ typically a letter, to print the non-indexed variables
+  -> Spray a               -- ^ the spray to be printed
+  -> String
+prettySprayX1X2X3 = showSprayX1X2X3' show
+
+-- | Pretty form of a spray with monomials displayed in the style of @"x.z^2"@; 
+-- you should rather use `prettyNumSpray` or `prettyQSpray` if you deal with 
+-- sprays with numeric coefficients
+--
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
 -- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
+-- >>> putStrLn $ prettySpray p
+-- (2)*x + (3)*y^2 + (-4)*z^3
+-- >>> putStrLn $ prettySpray (p ^+^ lone 4)
+-- (2)*x1 + (3)*x2^2 + (-4)*x3^3 + x4
+--
+-- prop> prettySpray spray == prettySprayXYZ ["x", "y", "z"] spray
+prettySpray :: (Show a) => Spray a -> String
+prettySpray = prettySprayXYZ ["x", "y", "z"]
+
+-- | Pretty form of a spray, with monomials shown as @"x1.x3^2"@; use 
+-- `prettySprayX1X2X3` to change the letter (or `prettyNumSprayX1X2X3` 
+-- or `prettyQSprayX1X2X3` if the coefficients are numeric)
+--
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
+-- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
 -- >>> putStrLn $ prettySpray' p
--- (2) x1 + (3) x2^2 + (-4) x3^3 
+-- (2)*x1 + (3)*x2^2 + (-4)*x3^3 
 prettySpray' :: Show a => Spray a -> String
-prettySpray' spray = unpack $ intercalate (pack " + ") terms
- where
-  terms           = map stringTerm 
-                        (sortBy (flip compare `on` fexpts) (HM.toList spray))
-  fexpts term     = exponents $ fst term
-  stringTerm term = append stringCoef'' (prettyPowers' pows)
-   where
-    pows         = exponents (fst term)
-    constant     = S.length pows == 0
-    stringCoef   = pack $ show (snd term)
-    stringCoef'  = cons '(' $ snoc stringCoef ')'
-    stringCoef'' = if constant then stringCoef' else snoc stringCoef' ' '
+prettySpray' = prettySprayX1X2X3 "x"
 
--- | Pretty form of a spray, with monomials shown as "x1x3^2", and with 
--- a user-defined showing function for the coefficients
+-- | showMonomialOld "x" [0, 2, 1] = x^(0, 2, 1)
+showMonomialsOld :: String -> [Seq Int] -> [String]
+showMonomialsOld var = map (showMonomialOld var) 
+  where
+    showMonomialOld :: String -> Seq Int -> String
+    showMonomialOld a pows = 
+      unpack $ append (pack x) (cons '(' $ snoc string ')')
+      where
+        x      = a ++ "^"
+        string = intercalate (pack ", ") (map (pack . show) (DF.toList pows))
+
+-- | Pretty form of a spray; you will probably prefer `prettySpray` or `prettySpray'`
 --
--- prop> prettySpray' p == prettySpray'' show p
-prettySpray'' :: (a -> String) -> Spray a -> String
-prettySpray'' showCoeff spray = unpack $ intercalate (pack " + ") terms
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
+-- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
+-- >>> putStrLn $ prettySpray'' "x" p
+-- (2)*x^(1) + (3)*x^(0, 2) + (-4)*x^(0, 0, 3)
+prettySpray'' 
+  :: Show a 
+  => String        -- ^ a string denoting the variables, e.g. \"x\"
+  -> Spray a       -- ^ the spray
+  -> String
+prettySpray'' var = showSpray show ("(", ")") (showMonomialsOld var)
+
+-- | Show a spray with numeric coefficients; this function is exported for 
+-- possible usage in other packages
+showNumSpray :: (Num a, Ord a)
+  => ([Seq Int] -> [String]) -- ^ function mapping a list of monomial exponents to a list of strings representing the monomials
+  -> (a -> String)           -- ^ function mapping a positive coefficient to a string
+  -> Spray a
+  -> String
+showNumSpray showMonomials showCoeff spray = 
+  if isZeroSpray spray 
+    then "0" 
+    else concat $ zipWith (++) stringSigns stringTerms
+  where
+    terms = sortBy (flip compare `on` (exponents . fst)) (HM.toList spray)
+    coeffs = map snd terms
+    (firstCoeff, otherCoeffs) = fromJust (uncons coeffs)
+    firstSign   = if firstCoeff > 0 then "" else "-"
+    otherSigns  = map (\x -> if x > 0 then " + " else " - ") otherCoeffs
+    stringSigns = firstSign : otherSigns
+    absCoeffs = map abs coeffs
+    powers = map (exponents . fst) terms
+    stringMonomials = showMonomials powers
+    stringTerms = zipWith f absCoeffs stringMonomials
+    f acoeff smonomial 
+      | smonomial == "" = showCoeff acoeff
+      | scoeff == ""    = smonomial
+      | otherwise       = scoeff ++ "*" ++ smonomial
+      where
+        scoeff = if acoeff == 1 then "" else showCoeff acoeff
+
+-- | showMonomialX1X2X3 "X" [0, 2, 1] = "X2^2.X3"
+showMonomialX1X2X3 :: String -> Seq Int -> Text
+showMonomialX1X2X3 x pows = x1x2x3
  where
-  terms           = map stringTerm 
-                        (sortBy (flip compare `on` fexpts) (HM.toList spray))
-  fexpts term     = exponents $ fst term
-  stringTerm term = append stringCoef'' (prettyPowers' pows)
-   where
-    pows         = exponents (fst term)
-    constant     = S.null pows
-    stringCoef   = pack $ showCoeff (snd term)
-    stringCoef'  = cons '(' $ snoc stringCoef ')'
-    stringCoef'' = if constant then stringCoef' else snoc stringCoef' '*'
+  f i p 
+    | p == 0    = pack ""
+    | p == 1    = pack $ x ++ show i
+    | otherwise = pack $ x ++ show i ++ "^" ++ show p
+  indices = S.findIndicesL (/= 0) pows
+  x1x2x3 = 
+    intercalate (pack ".") (map (\i -> f (i+1) (pows `index` i)) indices)
 
--- | prettyPowersXYZ [1, 2, 1] = XY^2Z
-prettyPowersXYZ :: Seq Int -> Text
-prettyPowersXYZ pows = if n <= 3 
-  then pack xyz
-  else error "prettyPowersXYZ: there is more than three variables"
+-- | showMonomialsX1X2X3 "X" [[0, 2, 1], [1, 2]] = ["X2^2.X3", "X1.X2"]
+showMonomialsX1X2X3 :: String -> [Seq Int] -> [String]
+showMonomialsX1X2X3 x = map (unpack . showMonomialX1X2X3 x)
+
+-- | showMonomialXYZ ["X", "Y", "Z"] 3 [1, 2, 1] = X.Y^2.Z
+--   showMonomialXYZ ["X", "Y", "Z"] 3 [1, 2, 1, 2] = X1.X2^2.X3.X4^2
+showMonomialXYZ :: [String] -> Int -> Seq Int -> Text
+showMonomialXYZ letters n pows = if n <= length letters
+  then xyz
+  else showMonomialX1X2X3 (letters !! 0) pows
  where
-  n     = S.length pows
-  gpows = growSequence pows n 3
   f letter p 
-    | p == 0    = ""
-    | p == 1    = letter
-    | otherwise = letter ++ "^" ++ show p
-  x   = f "X" (gpows `index` 0)
-  y   = f "Y" (gpows `index` 1)
-  z   = f "Z" (gpows `index` 2)
-  xyz = x ++ y ++ z
+    | p == 0    = pack ""
+    | p == 1    = pack letter
+    | otherwise = pack $ letter ++ "^" ++ show p
+  indices = S.findIndicesL (/= 0) pows
+  xyz = intercalate (pack ".") 
+        (map (\i -> f (letters!!i) (pows `index` i)) indices)
 
--- | Pretty form of a spray having at more three variables
+-- | showMonomialsXYZ ["X", "Y", "Z"] [[0, 2, 1], [1, 2]] = ["Y^2.Z", "X.Y^2"]
+showMonomialsXYZ :: [String] -> [Seq Int] -> [String]
+showMonomialsXYZ letters powers = map (unpack . showMonomialXYZ letters n) powers
+  where 
+    n = maximum (map S.length powers)
+
+-- | Pretty form of a spray with numeric coefficients, printing monomials as @"x1.x3^2"@
 --
--- >>> x :: lone 1 :: Spray Int
--- >>> y :: lone 2 :: Spray Int
--- >>> z :: lone 3 :: Spray Int
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
 -- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
--- >>> putStrLn $ prettySprayXYZ p
--- (2) X + (3) Y^2 + (-4) Z^3
-prettySprayXYZ :: (Show a) => Spray a -> String
-prettySprayXYZ spray = unpack $ intercalate (pack " + ") terms
- where
-  terms = map stringTerm (sortBy (flip compare `on` fexpts) (HM.toList spray))
-  fexpts term = exponents $ fst term
-  stringTerm term = append stringCoef'' (prettyPowersXYZ pows)
-   where
-    pows         = exponents (fst term)
-    constant     = S.null pows
-    stringCoef   = pack $ show (snd term)
-    stringCoef'  = cons '(' $ snoc stringCoef ')'
-    stringCoef'' = if constant then stringCoef' else snoc stringCoef' ' '
+-- >>> putStrLn $ prettyNumSprayX1X2X3 "x" p
+-- 2*x1 + 3*x2^2 - 4*x3^3 
+prettyNumSprayX1X2X3 :: (Num a, Ord a, Show a)
+  => String   -- ^ usually a letter such as @"x"@ to denote the non-indexed variables
+  -> Spray a
+  -> String
+prettyNumSprayX1X2X3 x = showNumSpray (showMonomialsX1X2X3 x) show
 
+-- | Pretty form of a spray with numeric coefficients, printing monomials as @"x.z^2"@
+-- if possible, i.e. if enough letters are provided, otherwise as @"x1.x3^2"@
+--
+-- >>> x = lone 1 :: Spray Int
+-- >>> y = lone 2 :: Spray Int
+-- >>> z = lone 3 :: Spray Int
+-- >>> w = lone 4 :: Spray Int
+-- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ 4*^z^**^3
+-- >>> putStrLn $ prettyNumSprayXYZ ["x","y","z"] p
+-- 2*x + 3*y^2 - 4*z^3 
+-- >>> putStrLn $ prettyNumSprayXYZ ["x","y","z"] (p ^+^ w)
+-- 2*x1 + 3*x2^2 - 4*x3^3 + x4
+-- >>> putStrLn $ prettyNumSprayXYZ ["a","b","c"] (p ^+^ w)
+-- 2*a1 + 3*a2^2 - 4*a3^3 + a4
+prettyNumSprayXYZ :: (Num a, Ord a, Show a)
+  => [String] -- ^ usually some letters, denoting the variables
+  -> Spray a
+  -> String
+prettyNumSprayXYZ letters = showNumSpray (showMonomialsXYZ letters) show
 
+-- | helper function for showQSpray
+showRatio :: Rational -> String
+showRatio q = if d == 1 
+  then show n 
+  else "(" ++ show n ++ "/" ++ show d ++ ")"
+  where
+    n = DR.numerator q
+    d = DR.denominator q 
+
+-- | helper function for showQSpray' 
+showRatio' :: (Eq a, Num a, Show a) => NumberRatio.T a -> String
+showRatio' q = if d == 1 
+  then show n 
+  else "(" ++ show n ++ "/" ++ show d ++ ")"
+  where
+    n = NumberRatio.numerator q
+    d = NumberRatio.denominator q 
+
+-- | Prints a `QSpray`; for internal usage but exported for usage in other packages
+showQSpray :: 
+   ([Seq Int] -> [String]) -- ^ function printing monomials
+  -> QSpray
+  -> String
+showQSpray showMonomials = showNumSpray showMonomials showRatio
+
+-- | Prints a `QSpray'`; for internal usage but exported for usage in other packages
+showQSpray' :: 
+   ([Seq Int] -> [String]) -- ^ function mapping a list of monomials exponents to a list of strings
+  -> QSpray'
+  -> String
+showQSpray' showMonomials = showNumSpray showMonomials showRatio'
+
+-- | Pretty form of a spray with rational coefficients, printing monomials in 
+-- the style of @"x1.x3^2"@
+--
+-- >>> x = lone 1 :: QSpray
+-- >>> y = lone 2 :: QSpray
+-- >>> z = lone 3 :: QSpray
+-- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ (4%3)*^z^**^3
+-- >>> putStrLn $ prettyQSprayX1X2X3 "x" p
+-- 2*x1 + 3*x2^2 - (4/3)*x3^3 
+prettyQSprayX1X2X3 :: 
+     String   -- ^ usually a letter such as @"x"@, to denote the non-indexed variables
+  -> QSpray
+  -> String
+prettyQSprayX1X2X3 x = showQSpray (showMonomialsX1X2X3 x)
+
+-- | Same as `prettyQSprayX1X2X3` but for a `QSpray'` spray
+prettyQSprayX1X2X3' :: 
+     String   -- ^ usually a letter such as @"x"@, to denote the non-indexed variables
+  -> QSpray'
+  -> String
+prettyQSprayX1X2X3' x = showQSpray' (showMonomialsX1X2X3 x)
+
+-- | Pretty form of a spray with rational coefficients, printing monomials in 
+-- the style of @"x.z^2"@ with the provided letters if possible, i.e. if enough 
+-- letters are provided, otherwise in the style @"x1.x3^2"@, taking the first 
+-- provided letter to denote the non-indexed variables
+--
+-- >>> x = lone 1 :: QSpray
+-- >>> y = lone 2 :: QSpray
+-- >>> z = lone 3 :: QSpray
+-- >>> p = 2*^x ^+^ 3*^y^**^2 ^-^ (4%3)*^z^**^3
+-- >>> putStrLn $ prettyQSprayXYZ ["x","y","z"] p
+-- 2*x + 3*y^2 - (4/3)*z^3 
+-- >>> putStrLn $ prettyQSprayXYZ ["x","y"] p
+-- 2*x1 + 3*x2^2 - (4%3)*x3^3
+-- >>> putStrLn $ prettyQSprayXYZ ["a","b"] p
+-- 2*a1 + 3*a2^2 - (4/3)*a3^3
+prettyQSprayXYZ :: 
+    [String]   -- ^ usually some letters, to denote the variables
+  -> QSpray
+  -> String
+prettyQSprayXYZ letters = showQSpray (showMonomialsXYZ letters)
+
+-- | Same as `prettyQSprayXYZ` but for a `QSpray'` spray
+prettyQSprayXYZ' :: 
+    [String]   -- ^ usually some letters, to denote the variables
+  -> QSpray'
+  -> String
+prettyQSprayXYZ' letters = showQSpray' (showMonomialsXYZ letters)
+
+-- | Pretty printing of a spray with rational coefficients
+-- prop> prettyQSpray == prettyQSprayXYZ ["x", "y", "z"]
+prettyQSpray :: QSpray -> String
+prettyQSpray = prettyQSprayXYZ ["x", "y", "z"]
+
+-- | Pretty printing of a spray with rational coefficients
+-- prop> prettyQSpray'' == prettyQSprayXYZ ["X", "Y", "Z"]
+prettyQSpray'' :: QSpray -> String
+prettyQSpray'' = prettyQSprayXYZ ["X", "Y", "Z"]
+
+-- | Pretty printing of a spray with rational coefficients
+-- prop> prettyQSpray' == prettyQSprayXYZ' ["x", "y", "z"]
+prettyQSpray' :: QSpray' -> String
+prettyQSpray' = prettyQSprayXYZ' ["x", "y", "z"]
+
+-- | Pretty printing of a spray with rational coefficients
+-- prop> prettyQSpray''' == prettyQSprayXYZ' ["X", "Y", "Z"]
+prettyQSpray''' :: QSpray' -> String
+prettyQSpray''' = prettyQSprayXYZ' ["X", "Y", "Z"]
+
+-- | Pretty printing of a spray with numeric coefficients
+-- prop> prettyNumSpray == prettyNumSprayXYZ ["x", "y", "z"]
+prettyNumSpray :: (Num a, Ord a, Show a) => Spray a -> String
+prettyNumSpray = prettyNumSprayXYZ ["x", "y", "z"]
+
+-- | Pretty printing of a spray with numeric coefficients
+-- prop> prettyNumSpray' == prettyNumSprayXYZ ["X", "Y", "Z"]
+prettyNumSpray' :: (Num a, Ord a, Show a) => Spray a -> String
+prettyNumSpray' = prettyNumSprayXYZ ["X", "Y", "Z"]
+
+
 -- misc -----------------------------------------------------------------------
 
 -- | Terms of a spray
@@ -880,7 +1315,13 @@   factorial n     = product [1 .. n]
   times k x       = AlgAdd.sum (replicate k x)
 
+-- | Whether two sprays are equal up to a scalar factor
+collinearSprays :: (Eq a, AlgField.C a) => Spray a -> Spray a -> Bool
+collinearSprays spray1 spray2 = r *^ spray2 == spray1
+  where
+    r = snd (leadingTerm spray1) AlgField./ snd (leadingTerm spray2)
 
+
 -- division stuff -------------------------------------------------------------
 
 -- | index of the maximum of a list
@@ -1111,7 +1552,7 @@       where
         rest = [ngbasis !! k | k <- [0 .. n-1] \\ [i]]
 
--- | Groebner basis (always minimal and possibly reduced)
+-- | Gröbner basis, always minimal and possibly reduced
 --
 -- prop> groebner sprays True == reduceGroebnerBasis (groebner sprays False)
 groebner 
@@ -1165,7 +1606,7 @@ -- | Elementary symmetric polynomial
 --
 -- >>> putStrLn $ prettySpray' (esPolynomial 3 2)
--- (1) x1x2 + (1) x1x3 + (1) x2x3
+-- (1)*x1x2 + (1)*x1x3 + (1)*x2x3
 esPolynomial 
   :: (AlgRing.C a, Eq a) 
   => Int -- ^ number of variables
@@ -1200,7 +1641,9 @@       where
         expts = S.replicate (j-1) 0 |> k
 
--- | Whether a spray is a symmetric polynomial
+-- | Whether a spray is a symmetric polynomial, an inefficient algorithm 
+-- (use the function with the same name in the /jackpolynomials/ package 
+-- if you need efficiency)
 isSymmetricSpray :: forall a. (AlgField.C a, Eq a) => Spray a -> Bool
 isSymmetricSpray spray = check1 && check2 
   where
@@ -1208,7 +1651,7 @@     indices = [1 .. n]
     gPolys = map (\i -> esPolynomial n i ^-^ lone (n + i)) indices
     gbasis  = groebner0 gPolys
-    spray'  = spray ^-^ (constantSpray (getConstantTerm spray))
+    spray'  = spray ^-^ constantSpray (getConstantTerm spray)
     g       = sprayDivisionRemainder spray' gbasis
     gpowers = HM.keys g
     check1  = minimum (map nvariables gpowers) > n
@@ -1230,11 +1673,10 @@                   => Spray a -> [Spray a] -> (Bool, Maybe (Spray a))
 isPolynomialOf spray sprays = result 
   where
-    n = numberOfVariables spray
-    n' = maximum $ map numberOfVariables sprays
+    nov = numberOfVariables spray
+    n   = maximum $ map numberOfVariables sprays
     result
-      | n > n'    = (False, Nothing)
-      | n < n'    = error "isPolynomialOf: not enough variables in the spray." 
+      | nov > n   = (False, Nothing)
       | otherwise = (checks, poly)
         where
           m            = length sprays
@@ -1300,7 +1742,7 @@     times :: a -> a -> a
     times x y = if x == AlgAdd.zero then AlgAdd.zero else x AlgRing.* y
 
--- | the coefficients of a spray as a univariate spray in x with 
+-- | the coefficients of a spray as a univariate spray in x_1 with 
 -- spray coefficients
 sprayCoefficients :: (Eq a, AlgRing.C a) => Spray a -> [Spray a]
 sprayCoefficients spray = 
@@ -1564,7 +2006,7 @@     leadingCoeff = 
       foldl1' (^+^) (zipWith (curry fromMonomial) powers'' coeffs'')
 
--- | pseudo-division of two sprays, assuming degA >= degB >= 0
+-- | Pseudo-division of two sprays, assuming degA >= degB >= 0
 pseudoDivision :: (Eq a, AlgRing.C a)
   => Int                           -- ^ number of variables
   -> Spray a                       -- ^ A
tests/Main.hs view
@@ -1,5 +1,6 @@-module Main where
-import qualified Algebra.Additive               as AlgAdd             
+module Main (main) where
+import qualified Algebra.Additive               as AlgAdd
+import qualified Algebra.Module                 as AlgMod
 import qualified Algebra.Ring                   as AlgRing      
 import           Approx                         ( assertApproxEqual )
 import           Data.Maybe                     ( fromJust )
@@ -24,6 +25,7 @@                                                   fromList,
                                                   toList,
                                                   bombieriSpray,
+                                                  collinearSprays,
                                                   derivSpray,
                                                   groebner,
                                                   fromRationalSpray,
@@ -38,14 +40,24 @@                                                   subresultants1,
                                                   sprayDivision,
                                                   gcdSpray,
-                                                  QSpray,
+                                                  QSpray',
                                                   SymbolicQSpray,
                                                   evalRatioOfPolynomials,
                                                   evalSymbolicSpray',
                                                   qpolyFromCoeffs,
-                                                  constQPoly, evalSymbolicSpray''
+                                                  constQPoly, 
+                                                  evalSymbolicSpray'',
+                                                  prettyQSpray,
+                                                  prettyQSprayX1X2X3,
+                                                  prettySpray,
+                                                  prettySpray'',
+                                                  outerQVariable,
+                                                  constQPoly,
+                                                  prettySymbolicQSpray',
+                                                  (*.)
                                                 )
 import           Number.Ratio                   ( T ( (:%) ) )
+import qualified Number.Ratio                   as NR
 import           Test.Tasty                     ( defaultMain
                                                 , testGroup
                                                 )
@@ -58,11 +70,22 @@ main = defaultMain $ testGroup
   "Testing hspray"
 
-  [ testCase "bombieriSpray" $ do
+  [ 
+    testCase "collinearSprays" $ do
       let
         x = lone 1 :: Spray Rational
         y = lone 2 :: Spray Rational
         z = lone 3 :: Spray Rational
+        spray1 =
+          (2 % 1) *^ ((2 % 1) *^ (x ^**^ 3 ^*^ y ^**^ 2)) ^+^ (4 % 1) *^ z ^+^ (5 % 1) *^ unitSpray
+        spray2 = 121 *^ spray1
+      assertBool "" (collinearSprays spray1 spray2)
+    
+    , testCase "bombieriSpray" $ do
+      let
+        x = lone 1 :: Spray Rational
+        y = lone 2 :: Spray Rational
+        z = lone 3 :: Spray Rational
         poly =
           (2 % 1) *^ ((2 % 1) *^ (x ^**^ 3 ^*^ y ^**^ 2)) ^+^ (4 % 1) *^ z ^+^ (5 % 1) *^ unitSpray
         bpoly =
@@ -158,6 +181,15 @@         p = p1 ^*^ p2 ^+^ unitSpray
       assertEqual "" (isPolynomialOf p [p1, p2]) (True, Just $ x ^*^ y ^+^ unitSpray),
 
+    testCase "isPolynomialOf - 2" $ do
+      let
+        x = lone 1 :: Spray Rational
+        y = lone 2 :: Spray Rational
+        z = lone 3 :: Spray Rational
+      assertEqual "" 
+        (isPolynomialOf x [x ^+^ y^*^z, y, z]) 
+        (True, Just $ x ^-^ y^*^z),
+
     testCase "power sum polynomials" $ do
       let
         x = lone 1 :: Spray Rational
@@ -345,7 +377,7 @@         g :: (Eq a, AlgRing.C a) => Spray a -> Spray a -> Spray a -> (a, a, a) -> (a, a)
         g px py pz (x, y, z) = (evalSpray f1 [x, y, AlgAdd.zero], evalSpray f2 [AlgAdd.zero, AlgAdd.zero, z])
           where (f1, f2) = f px py pz
-        (r1, r2) = g (lone 1 :: QSpray) (lone 2) (lone 3) (2, 3, 4) 
+        (r1, r2) = g (lone 1 :: QSpray') (lone 2) (lone 3) (2, 3, 4) 
         r = evalRatioOfPolynomials 5 rop1 AlgRing.* r1  AlgAdd.+  evalRatioOfPolynomials 5 rop2 AlgRing.* r2
         (f1', f2')  = f (lone 1 :: SymbolicQSpray) (lone 2) (lone 3)
         symSpray  = rop1 *^ f1'  ^+^  rop2 *^ f2' 
@@ -353,6 +385,78 @@         rop1' = evalSymbolicSpray'' f1' [2, 3]
         rop2' = evalSymbolicSpray'' f2' [0, 0, 4]
         r'' = evalRatioOfPolynomials 5 (rop1 AlgRing.* rop1' AlgAdd.+ rop2 AlgRing.* rop2')
-      assertEqual "" (r, r') (r', r'') 
+      assertEqual "" (r, r') (r', r''),
+
+    testCase "pretty spray" $ do
+      let
+        x = lone 1 :: Spray Rational
+        y = lone 2 :: Spray Rational
+        z = lone 3 :: Spray Rational
+        p1 = ((2%3) *^ x^**^3) ^*^ y  ^-^  x^**^2  ^+^  y ^*^ z  ^-^  (2%3) *^ unitSpray
+        p2 = (3%2) *^ p1
+        p3 = AlgAdd.negate $ 
+          swapVariables (1, 3) $ 
+            p2  ^+^  unitSpray  ^-^  (x^**^3 ^*^ y  ^-^  ((3%2) *^ x^**^2))
+        strings = 
+          [
+            prettyQSpray (zeroSpray ^*^ p1)
+          , prettyQSpray p1
+          , prettyQSpray (AlgAdd.negate p2)
+          , prettyQSpray (p2  ^+^  lone 4)
+          , prettyQSpray p3
+          , " ---------- "
+          , prettyQSprayX1X2X3 "a" (zeroSpray ^*^ p1)
+          , prettyQSprayX1X2X3 "a" p1
+          , prettyQSprayX1X2X3 "a" (p2  ^+^  lone 4)
+          , prettyQSprayX1X2X3 "a" p3
+          , " ---------- "
+          , prettySpray (zeroSpray ^*^ p1)
+          , prettySpray p1
+          , prettySpray (p2  ^+^  lone 4)
+          , prettySpray p3
+          , " ---------- "
+          , prettySpray'' "w" (zeroSpray ^*^ p1)
+          , prettySpray'' "w" p1
+          , prettySpray'' "w" (p2  ^+^  lone 4)
+          , prettySpray'' "w" p3
+          ]
+        strings' =
+          [
+            "0"
+          , "(2/3)*x^3.y - x^2 + y.z - (2/3)"
+          , "-x^3.y + (3/2)*x^2 - (3/2)*y.z + 1"
+          , "x1^3.x2 - (3/2)*x1^2 + (3/2)*x2.x3 + x4 - 1"
+          , "-(3/2)*x.y"
+          , " ---------- "
+          , "0"
+          , "(2/3)*a1^3.a2 - a1^2 + a2.a3 - (2/3)"
+          , "a1^3.a2 - (3/2)*a1^2 + (3/2)*a2.a3 + a4 - 1"
+          , "-(3/2)*a1.a2"
+          , " ---------- "
+          , "0"
+          , "(2 % 3)*x^3.y + ((-1) % 1)*x^2 + (1 % 1)*y.z + ((-2) % 3)"
+          , "(1 % 1)*x1^3.x2 + ((-3) % 2)*x1^2 + (3 % 2)*x2.x3 + (1 % 1)*x4 + ((-1) % 1)"
+          , "((-3) % 2)*x.y"
+          , " ---------- "
+          , "0"
+          , "(2 % 3)*w^(3, 1) + ((-1) % 1)*w^(2) + (1 % 1)*w^(0, 1, 1) + ((-2) % 3)*w^()"
+          , "(1 % 1)*w^(3, 1) + ((-3) % 2)*w^(2) + (3 % 2)*w^(0, 1, 1) + (1 % 1)*w^(0, 0, 0, 1) + ((-1) % 1)*w^()"
+          , "((-3) % 2)*w^(1, 1)"  
+          ]
+      assertEqual "" strings strings',
+
+    testCase "prettySymbolicQSpray'" $ do
+      let
+        x = lone 1 :: SymbolicQSpray 
+        y = lone 2 :: SymbolicQSpray 
+        z = lone 3 :: SymbolicQSpray 
+        a = outerQVariable  
+        sSpray 
+          = ((4 NR.% 5) *. (a :% (a AlgRing.^ 2 AlgAdd.+ AlgRing.one))) AlgMod.*> (x^**^2 ^-^ y^**^2)  
+            ^+^  (constQPoly (2 NR.% 3) AlgRing.* a) AlgMod.*> (y ^*^ z)
+        string = prettySymbolicQSpray' "a" sSpray
+        string' = 
+          "{ [ (4/5)*a ] %//% [ a^2 + 1 ] }*X^2 + { [ -(4/5)*a ] %//% [ a^2 + 1 ] }*Y^2 + { (2/3)*a }*Y.Z"
+      assertEqual "" string string'
 
   ]