@@ -5,7 +5,7 @@ export LaurentPolynomial
5
5
6
6
A [Laurent](https://en.wikipedia.org/wiki/Laurent_polynomial) polynomial is of the form `a_{m}x^m + ... + a_{n}x^n` where `m,n` are integers (not necessarily positive) with ` m <= n`.
7
7
8
- The `coeffs` specify `a_{m}, a_{m-1}, ..., a_{n}`. Rhe range specified is of the form `m:n`, if left empty, `0:length(coeffs)-1` is used (i.e., the coefficients refer to the standard basis).
8
+ The `coeffs` specify `a_{m}, a_{m-1}, ..., a_{n}`. The range specified is of the form `m:n`, if left empty, `0:length(coeffs)-1` is used (i.e., the coefficients refer to the standard basis). Alternatively, the coefficients can be specified using an `OffsetVector` from the `OffsetArrays` package .
9
9
10
10
Laurent polynomials and standard basis polynomials promote to Laurent polynomials. Laurent polynomials may be converted to a standard basis polynomial when `m >= 0`
11
11
.
94
94
95
95
@register LaurentPolynomial
96
96
97
+ # Add interface for OffsetArray
98
+ function LaurentPolynomial {T} (coeffs:: OffsetArray{S, 1, Array{S,1}} , var:: SymbolLike = :x ) where {T, S}
99
+ m,n = axes (coeffs, 1 )
100
+ LaurentPolynomial {T} (T .(coeffs. parent), m: n, Symbol (var))
101
+ end
102
+ function LaurentPolynomial (coeffs:: OffsetArray{S, 1, Array{S,1}} , var:: SymbolLike = :x ) where {S}
103
+ LaurentPolynomial {S} (coeffs, var)
104
+ end
105
+
106
+
107
+
97
108
function LaurentPolynomial {T} (coeffs:: AbstractVector{S} ,
98
109
rng:: UnitRange{Int64} = 0 : length (coeffs)- 1 ,
99
110
var:: Symbol = :x ) where {T <: Number , S <: Number }
@@ -109,11 +120,11 @@ function LaurentPolynomial(coeffs::AbstractVector{T}, var::SymbolLike=:x) where
109
120
end
110
121
111
122
# # Alternate interface
112
- Polynomial (coeffs:: AbstractVector{T} , rng :: UnitRange , var:: SymbolLike = :x ) where {T <: Number } =
113
- LaurentPolynomial {T} (coeffs, rng, Symbol ( var) )
123
+ Polynomial (coeffs:: OffsetArray{T,1,Array{T,1}} , var:: SymbolLike = :x ) where {T <: Number } =
124
+ LaurentPolynomial {T} (coeffs, var)
114
125
115
- Polynomial {T} (coeffs:: AbstractVector{S} , rng :: UnitRange , var:: SymbolLike = :x ) where {T <: Number , S <: Number } =
116
- LaurentPolynomial {T} (T .( coeffs), rng, Symbol ( var) )
126
+ Polynomial {T} (coeffs:: OffsetArray{S,1,Array{S,1}} , var:: SymbolLike = :x ) where {T <: Number , S <: Number } =
127
+ LaurentPolynomial {T} (coeffs, var)
117
128
118
129
# #
119
130
# # conversion
@@ -267,6 +278,122 @@ function showterm(io::IO, ::Type{<:LaurentPolynomial}, pj::T, var, j, first::Boo
267
278
end
268
279
269
280
281
+ # #
282
+ # # ---- Conjugation has different defintions
283
+ # #
284
+
285
+ """
286
+ conj(p)
287
+
288
+ This satisfies `conj(p(x)) = conj(p)(conj(x)) = p̄(conj(x))` or `p̄(x) = (conj ∘ p ∘ conj)(x)`
289
+
290
+ Examples
291
+ ```jldoctest
292
+ julia> z = variable(LaurentPolynomial, :z)
293
+ LaurentPolynomial(z)
294
+
295
+ julia> p = LaurentPolynomial([im, 1+im, 2 + im], -1:1, :z)
296
+ LaurentPolynomial(im*z⁻¹ + (1 + 1im) + (2 + 1im)*z)
297
+
298
+ julia> conj(p)(conj(z)) ≈ conj(p(z))
299
+ true
300
+
301
+ julia> conj(p)(z) ≈ (conj ∘ p ∘ conj)(z)
302
+ true
303
+ ```
304
+ """
305
+ function LinearAlgebra. conj (p:: P ) where {P <: LaurentPolynomial }
306
+ ps = coeffs (p)
307
+ m,n = extrema (p)
308
+ ⟒ (P)(conj (ps),m: n, p. var)
309
+ end
310
+
311
+
312
+ """
313
+ paraconj(p)
314
+
315
+ [cf.](https://ccrma.stanford.edu/~jos/filters/Paraunitary_FiltersC_3.html)
316
+
317
+ Call `p̂ = paraconj(p)` and `p̄` = conj(p)`, then this satisfies
318
+ `conj(p(z)) = p̂(1/conj(z))` or `p̂(z) = p̄(1/z) = (conj ∘ p ∘ conj ∘ inf)(z)`.
319
+
320
+ Examples:
321
+
322
+ ```jldoctest
323
+ julia> z = variable(LaurentPolynomial, :z)
324
+ LaurentPolynomial(z)
325
+
326
+ julia> h = LaurentPolynomial([1,1], -1:0, :z)
327
+ LaurentPolynomial(z⁻¹ + 1)
328
+
329
+ julia> Polynomials.paraconj(h)(z) ≈ 1 + z ≈ LaurentPolynomial([1,1], 0:1, :z)
330
+ true
331
+
332
+ julia> h = LaurentPolynomial([3,2im,1], -2:0, :z)
333
+ LaurentPolynomial(3*z⁻² + 2im*z⁻¹ + 1)
334
+
335
+ julia> Polynomials.paraconj(h)(z) ≈ 1 - 2im*z + 3z^2 ≈ LaurentPolynomial([1, -2im, 3], 0:2, :z)
336
+ true
337
+
338
+ julia> Polynomials.paraconj(h)(z) ≈ (conj ∘ h ∘ conj ∘ inv)(z)
339
+ true
340
+ """
341
+ function paraconj (p:: LaurentPolynomial )
342
+ cs = p. coeffs
343
+ ds = adjoint .(cs)
344
+ m,n = extrema (p)
345
+ LaurentPolynomial (reverse (ds), - n: - m, p. var)
346
+ end
347
+
348
+ """
349
+ cconj(p)
350
+
351
+ Conjugation of a polynomial with respect to the imaginary axis.
352
+
353
+ The `cconj` of a polynomial, `p̃`, conjugates the coefficients and applies `s -> -s`. That is `cconj(p)(s) = conj(p)(-s)`.
354
+
355
+ This satisfies for *imaginary* `s`: `conj(p(s)) = p̃(s) = (conj ∘ p)(s) = cconj(p)(s) `
356
+
357
+ [ref](https://github.com/hurak/PolynomialEquations.jl#symmetrix-conjugate-equation-continuous-time-case)
358
+
359
+ Examples:
360
+ ```jldoctest
361
+ julia> s = 2im
362
+ 0 + 2im
363
+
364
+ julia> p = LaurentPolynomial([im,-1, -im, 1], 1:2, :s)
365
+ LaurentPolynomial(im*s - s² - im*s³ + s⁴)
366
+
367
+ julia> Polynomials.cconj(p)(s) ≈ conj(p(s))
368
+ true
369
+
370
+ julia> a = LaurentPolynomial([-0.12, -0.29, 1],:s)
371
+ LaurentPolynomial(-0.12 - 0.29*s + 1.0*s²)
372
+
373
+ julia> b = LaurentPolynomial([1.86, -0.34, -1.14, -0.21, 1.19, -1.12],:s)
374
+ LaurentPolynomial(1.86 - 0.34*s - 1.14*s² - 0.21*s³ + 1.19*s⁴ - 1.12*s⁵)
375
+
376
+ julia> x = LaurentPolynomial([-15.5, 50.0096551724139, 1.19], :s)
377
+ LaurentPolynomial(-15.5 + 50.0096551724139*s + 1.19*s²)
378
+
379
+ julia> Polynomials.cconj(a) * x + a * Polynomials.cconj(x) ≈ b + Polynomials.cconj(b)
380
+ true
381
+ ```
382
+
383
+ """
384
+ function cconj (p:: LaurentPolynomial )
385
+ ps = conj .(coeffs (p))
386
+ m,n = extrema (p)
387
+ for i in m: n
388
+ if isodd (i)
389
+ ps[i+ 1 - m] *= - 1
390
+ end
391
+ end
392
+ LaurentPolynomial (ps, m: n, p. var)
393
+ end
394
+
395
+
396
+
270
397
# #
271
398
# # ----
272
399
# #
@@ -279,10 +406,13 @@ function (p::LaurentPolynomial{T})(x::S) where {T,S}
279
406
if m >= 0
280
407
evalpoly (x, NTuple {n+1,T} (p[i] for i in 0 : n))
281
408
elseif n <= 0
282
- evalpoly (inv (x), NTuple {m+1,T} (p[i] for i in 0 : - 1 : m))
409
+ evalpoly (inv (x), NTuple {- m+1,T} (p[i] for i in 0 : - 1 : m))
283
410
else
284
411
# eval pl(x) = a_mx^m + ...+ a_0 at 1/x; pr(x) = a_0 + a_1x + ... + a_nx^n at x; subtract a_0
285
- evalpoly (inv (x), NTuple {-m+1,T} (p[i] for i in 0 : - 1 : m)) + evalpoly (x, NTuple {n+1,T} (p[i] for i in 0 : n)) - p[0 ]
412
+ l = evalpoly (inv (x), NTuple {-m+1,T} (p[i] for i in 0 : - 1 : m))
413
+ r = evalpoly (x, NTuple {n+1,T} (p[i] for i in 0 : n))
414
+ mid = p[0 ]
415
+ l + r - mid
286
416
end
287
417
end
288
418
@@ -426,3 +556,20 @@ function integrate(p::P, k::S) where {T, P<: LaurentPolynomial{T}, S<:Number}
426
556
return ⟒ (P)(as, m: n, p. var)
427
557
428
558
end
559
+
560
+
561
+ function Base. gcd (p:: LaurentPolynomial{T} , q:: LaurentPolynomial{T} , args... ; kwargs... ) where {T}
562
+ mp, Mp = extrema (p)
563
+ mq, Mq = extrema (q)
564
+ if mp < 0 || mq < 0
565
+ throw (ArgumentError (" GCD is not defined when there are `x⁻¹` terms" ))
566
+ end
567
+
568
+ degree (p) == 0 && return iszero (p) ? q : one (q)
569
+ degree (q) == 0 && return iszero (q) ? p : one (p)
570
+ check_same_variable (p,q) || throw (ArgumentError (" p and q have different symbols" ))
571
+
572
+ pp, qq = convert (Polynomial, p), convert (Polynomial, q)
573
+ u = gcd (pp, qq, args... , kwargs... )
574
+ return LaurentPolynomial (coeffs (u), p. var)
575
+ end
0 commit comments