Getting Started
First we import the library
[1]:
import biquaternion_py as bq
Creating Biquaternions
Biquaternions can be created via arrays, comma separated arguments or by inputing a BiQuaternion
object. If less than 8 arguments are given, the rest are assumed to be 0.
[2]:
a = bq.BiQuaternion([1,2,3,4,5,6,7,8])
b = bq.BiQuaternion(1,1,1,1,1,1,1,1)
c = bq.BiQuaternion(1,2,3,4)
d = bq.BiQuaternion([3,1,4,1,5])
e = bq.BiQuaternion(a-c)
print(a, "\n", b, "\n", c, "\n", d, "\n", e)
(( 1 ) + ( 2 ) * i + ( 3 ) * j + ( 4 ) * k) + eps * (( 5 ) + ( 6 ) * i + ( 7 ) * j + ( 8 ) * k)
(( 1 ) + ( 1 ) * i + ( 1 ) * j + ( 1 ) * k) + eps * (( 1 ) + ( 1 ) * i + ( 1 ) * j + ( 1 ) * k)
(( 1 ) + ( 2 ) * i + ( 3 ) * j + ( 4 ) * k) + eps * (( 0 ) + ( 0 ) * i + ( 0 ) * j + ( 0 ) * k)
(( 3 ) + ( 1 ) * i + ( 4 ) * j + ( 1 ) * k) + eps * (( 5 ) + ( 0 ) * i + ( 0 ) * j + ( 0 ) * k)
(( 0 ) + ( 0 ) * i + ( 0 ) * j + ( 0 ) * k) + eps * (( 5 ) + ( 6 ) * i + ( 7 ) * j + ( 8 ) * k)
Basic arithmetic
All basic operations between dual quaternions are supported. Addition, subtraction, multiplication and division, if the divisor is an invertible dual quaternion.
[3]:
a+b
[3]:
[4]:
a-b
[4]:
a*b
[5]:
a/b
[5]:
Also basic unary operations such as quaternion conjugation, epsilon conjugation and finding of inverses are implemented
[6]:
a.conjugate()
[6]:
[7]:
a.eps_conjugate()
[7]:
[8]:
a.inv()
[8]:
Sympy integration
biquaternion_py
can easily work sympy
for symbolic computations.
[9]:
import sympy as sy
x_ind = sy.symbols("x:8")
y_ind = sy.symbols("y:8")
z_ind = sy.symbols("z:8")
x = bq.BiQuaternion(x_ind)
y = bq.BiQuaternion(y_ind)
z = bq.BiQuaternion(z_ind)
[10]:
x
[10]:
Polynomials
Thanks to the sympy integration, polynomials can easliy be constructed.
[11]:
t = sy.symbols("t")
s = sy.symbols("s")
[12]:
p = bq.Poly(x*t**2 + y*t + z, t)
print(p)
Polynomials also support all basic operations of the biquaternions.
Multivariate polynomials can also be declared.
[13]:
q = bq.Poly(x*t**2 + y*t*s + z*s**2, t,s)
[14]:
print(q)
Poly((( s**2*z0 + s*t*y0 + t**2*x0 ) + ( s**2*z1 + s*t*y1 + t**2*x1 ) * i + ( s**2*z2 + s*t*y2 + t**2*x2 ) * j + ( s**2*z3 + s*t*y3 + t**2*x3 ) * k) + eps * (( s**2*z4 + s*t*y4 + t**2*x4 ) + ( s**2*z5 + s*t*y5 + t**2*x5 ) * i + ( s**2*z6 + s*t*y6 + t**2*x6 ) * j + ( s**2*z7 + s*t*y7 + t**2*x7 ) * k),[t, s])
The coefficients of polynomials can be calculated with respect to specific variables, or for all. In the second case the list will be ordered the same way as the variables are ordered.
[15]:
q.all_indet_coeffs(t)
[15]:
[(( s**2*z0 ) + ( s**2*z1 ) * II + ( s**2*z2 ) * JJ + ( s**2*z3 ) * KK) + EE * (( s**2*z4 ) + ( s**2*z5 ) * II + ( s**2*z6 ) * JJ + ( s**2*z7 ) * KK),
(( s*y0 ) + ( s*y1 ) * II + ( s*y2 ) * JJ + ( s*y3 ) * KK) + EE * (( s*y4 ) + ( s*y5 ) * II + ( s*y6 ) * JJ + ( s*y7 ) * KK),
(( x0 ) + ( x1 ) * II + ( x2 ) * JJ + ( x3 ) * KK) + EE * (( x4 ) + ( x5 ) * II + ( x6 ) * JJ + ( x7 ) * KK)]
[16]:
q.all_coeffs()
[16]:
[[(( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK) + EE * (( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK),
(( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK) + EE * (( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK),
(( z0 ) + ( z1 ) * II + ( z2 ) * JJ + ( z3 ) * KK) + EE * (( z4 ) + ( z5 ) * II + ( z6 ) * JJ + ( z7 ) * KK)],
[(( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK) + EE * (( 0 ) + ( 0 ) * II + ( 0 ) * JJ + ( 0 ) * KK),
(( y0 ) + ( y1 ) * II + ( y2 ) * JJ + ( y3 ) * KK) + EE * (( y4 ) + ( y5 ) * II + ( y6 ) * JJ + ( y7 ) * KK)],
[(( x0 ) + ( x1 ) * II + ( x2 ) * JJ + ( x3 ) * KK) + EE * (( x4 ) + ( x5 ) * II + ( x6 ) * JJ + ( x7 ) * KK)]]
Polynomial factorization
Given a polynomial \(p\) with real norm, we want to calculate a factorization of it. This can be achived in the following way.
Let us first define the polynomial.
[17]:
h1 = bq.rand_rational() + bq.rand_line()
h2 = bq.rand_rational() + bq.rand_line()
h3 = bq.rand_rational() + bq.rand_line()
p = bq.Poly((t-h1)*(t-h2)*(t-h3),t)
To calculate a factorization we first need to find the irreducible factors of the norm polynomial. Since the norm is supposed to be real, we refine the result to eliminate numerical errors and only take the scalar part of the norm polynomial. Also since irreducible_factors
uses a sympy algorithm to find the irreducible factors, it needs the norm polynomial to be of numeric type and not of BiQuaternion
.
[18]:
norm_poly = bq.Poly(p.norm().poly.scal, *p.indets)
Now we can find the irreducible factors of the norm polynomial, which will generate our factorization of \(p\).
[19]:
_, factors = bq.irreducible_factors(norm_poly)
This gives a list of irreducible factors. Different permutations of these factors give different factorizations. The factorizations are given as a list of linear polynomials.
[20]:
factorization1 = bq.factorize_from_list(p, factors)
factorization2 = bq.factorize_from_list(p, factors[::-1])
[21]:
factorization1
[21]:
[Poly((( t + 1 ) + ( 32311809984245/44725094719148 ) * II + ( 34578632525362/33543821039361 ) * JJ + ( 351896696664851/805051704944664 ) * KK) + EE * (( 0 ) + ( -44284801123314932780983936589/10126691369286099104801594889 ) * II + ( 29680483103375341676412817091/13502255159048132139735459852 ) * JJ + ( 2299604199269621439590760626/1125187929920677678311288321 ) * KK),[t]),
Poly((( t + 3/8 ) + ( 4078668814369778519021530352221/24129008318361963739967827133700 ) * II + ( 222568068782882460815700835949/8043002772787321246655942377900 ) * JJ + ( 379078450896418831103352832781/3619351247754294560995174070055 ) * KK) + EE * (( 0 ) + ( 93153509251375240617392298755023996825833280903051939224028186/65498517273102844647276809738090807963757311156549170238515125 ) * II + ( -5261551565198463547793840539880940884262623128351926304656166/21832839091034281549092269912696935987919103718849723412838375 ) * JJ + ( -9744759479815913735884924427374697576551688099866177736541233/4366567818206856309818453982539387197583820743769944682567675 ) * KK),[t]),
Poly((( t - 4 ) + ( 879901041143907952/1258823927887787975 ) * II + ( -116364559407336308423/22658830701980183550 ) * JJ + ( 4828352527998813938/755294356732672785 ) * KK) + EE * (( 0 ) + ( 7173871441066101040305204903230527877/1629913043749205643278320942513303500 ) * II + ( -208038679024699983679882448499348562/58211180133900201545654319375475125 ) * JJ + ( -1639181395297842644170893262659911797/488973913124761692983496282753991050 ) * KK),[t])]
We can now check, if these factorizations are indeed correct.
[22]:
poly1 = 1
for fac in factorization1:
poly1 *= fac
poly2 = 1
for fac in factorization2:
poly2 *= fac
[23]:
p == poly1 == poly2
[23]:
True