From 18db86154b46cf74895254a62021fdd507b382de Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 2 Oct 2019 06:48:37 +0200 Subject: [PATCH] Fixes for Julia 1.0 Signed-off-by: neveritt --- .travis.yml | 8 +- Manifest.toml | 138 +++++++++++++++++++ Project.toml | 25 ++++ REQUIRE | 4 - appveyor.yml | 53 +++----- src/RationalFunctions.jl | 8 +- src/conversions.jl | 39 +++--- src/methods.jl | 280 +++++++++++++++++---------------------- src/plotting.jl | 3 +- src/printing.jl | 10 +- src/type.jl | 100 +++++++------- test/runtests.jl | 103 +++++++------- 12 files changed, 443 insertions(+), 328 deletions(-) create mode 100644 Manifest.toml create mode 100644 Project.toml delete mode 100644 REQUIRE diff --git a/.travis.yml b/.travis.yml index b5ac6b6..b7d437d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,11 @@ os: - osx julia: - - 0.4 - - 0.5 - - 0.6 + - 1.0 + - 1.1 + - 1.2 + - 1.3 + - 1.4 - nightly matrix: diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..db6704e --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,138 @@ +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[BinaryProvider]] +deps = ["Libdl", "Logging", "SHA"] +git-tree-sha1 = "ecdec412a9abc8db54c0efc5548c64dfce072058" +uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232" +version = "0.5.10" + +[[Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "7c7f4cda0d58ec999189d70f5ee500348c4b4df1" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "3.16.0" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[Distributed]] +deps = ["LinearAlgebra", "Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[ExprTools]] +git-tree-sha1 = "7fce513fcda766962ff67c5596cb16c463dfd371" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.2" + +[[EzXML]] +deps = ["BinaryProvider", "Libdl", "Printf"] +git-tree-sha1 = "ed53ce1ddb862193b2bd3851dfa108513aab2d5c" +uuid = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615" +version = "1.0.0" + +[[InteractiveUtils]] +deps = ["LinearAlgebra", "Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[Intervals]] +deps = ["Dates", "Printf", "RecipesBase", "Serialization", "TimeZones"] +git-tree-sha1 = "9da845579d1dce4ce5118008c3fe6df17260bb46" +uuid = "d8418881-c3e1-53bb-8760-2df7ec849ed5" +version = "1.4.2" + +[[LibGit2]] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[LinearAlgebra]] +deps = ["Libdl"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[Mocking]] +deps = ["ExprTools"] +git-tree-sha1 = "916b850daad0d46b8c71f65f719c49957e9513ed" +uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" +version = "0.7.1" + +[[Pkg]] +deps = ["Dates", "LibGit2", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[Polynomials]] +deps = ["Intervals", "LinearAlgebra", "RecipesBase"] +git-tree-sha1 = "a88e0eddef9202b651f4b60b37b59ca67bb49516" +uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" +version = "0.7.0" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[RecipesBase]] +git-tree-sha1 = "6ee6c35fe69e79e17c455a386c1ccdc66d9f7da4" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.1.0" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[TimeZones]] +deps = ["Dates", "EzXML", "Mocking", "Pkg", "Printf", "RecipesBase", "Serialization", "Unicode"] +git-tree-sha1 = "338ddbb2b9b50a9a423ba6c3fad1824553535988" +uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" +version = "1.3.2" + +[[UUIDs]] +deps = ["Random"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..d1ab36b --- /dev/null +++ b/Project.toml @@ -0,0 +1,25 @@ +name = "RationalFunctions" +uuid = "a89fc88f-fc1e-5208-8949-7a3f8ddd21cd" +authors = ["Arda Aytekin "] +version = "0.1.1" + +[deps] +Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" +RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" + +[compat] +Compat = "≥ 0.8.0" +GR = "≥ 0.19.0" +Plots = "≥ 0.8.2" +Polynomials = "≥ 0.7.0" +julia = "≥ 1.0.5" + +[extras] +GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["GR", "Plots", "Test"] diff --git a/REQUIRE b/REQUIRE deleted file mode 100644 index e8f8fd0..0000000 --- a/REQUIRE +++ /dev/null @@ -1,4 +0,0 @@ -julia 0.4 -Compat 0.8.0 -Polynomials 0.1.2 -RecipesBase diff --git a/appveyor.yml b/appveyor.yml index e6640be..4c35940 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,35 +1,26 @@ environment: matrix: - - platform: x86 - julia: 0.4 - link: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe" - - platform: x86 - julia: 0.5 - link: "julialang/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe" - - platform: x86 - julia: 0.6 - link: "julialang/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" - - platform: x86 - julia: nightly - link: "julianightlies/bin/winnt/x86/julia-latest-win32.exe" - - platform: x64 - julia: 0.4 - link: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe" - - platform: x64 - julia: 0.5 - link: "julialang/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe" - - platform: x64 - julia: 0.6 - link: "julialang/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe" - - platform: x64 - julia: nightly - link: "julianightlies/bin/winnt/x64/julia-latest-win64.exe" + - julia_version: 1.0 + - julia_version: 1.1 + - julia_version: 1.2 + - julia_version: 1.3 + - julia_version: 1.4 + - julia_version: nightly + +platform: + - x86 # 32-bit + - x64 # 64-bit matrix: fast_finish: true allow_failures: - julia: nightly +branches: + only: + - master + - /release-.*/ + notifications: - provider: Email on_build_success: false @@ -37,19 +28,15 @@ notifications: on_build_status_changed: false install: - - ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12" - - ps: (new-object net.webclient).DownloadFile( - $("http://s3.amazonaws.com/"+$env:link), - "C:\projects\julia-binary.exe") - - C:\projects\julia-binary.exe /S /D=C:\projects\julia + - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1")) build_script: - - IF EXIST .git\shallow (git fetch --unshallow) - - C:\projects\julia\bin\julia -e "versioninfo(); - Pkg.clone(pwd(), \"RationalFunctions\"); Pkg.build(\"RationalFunctions\")" + - echo "%JL_BUILD_SCRIPT%" + - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%" test_script: - - C:\projects\julia\bin\julia -e "Pkg.test(\"RationalFunctions\")" + - echo "%JL_TEST_SCRIPT%" + - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%" - C:\projects\julia\bin\julia -e "Pkg.dir(\"RationalFunctions\") |> println" > folder.txt - set /p TEST_FOLDER= Tuple{Poly,Poly,Val} + variable(r::RationalFunction) -> Tuple{Polynomial,Polynomial,Val} Return the variables of the numerator and denominator polynomials of `r` as well as the conjugation property. """ -variable{T,S,U,V}(::Type{RationalFunction{Val{T},Val{S},U,V}}) = - (variable(U, T), variable(V, T), Val{S}) -variable{T,S,U,V}(r::RationalFunction{Val{T},Val{S},U,V}) = - (variable(U, T), variable(V, T), Val{S}) +variable(::Type{RationalFunction{Val{T},Val{S},U,V}}) where {T,S,U,V} = + (variable(Polynomial{U}, T), variable(Polynomial{V}, T), Val{S}) +variable(r::RationalFunction{Val{T},Val{S},U,V}) where {T,S,U,V} = + (variable(Polynomial{U}, T), variable(Polynomial{V}, T), Val{S}) """ - num(r::RationalFunction) -> Poly + numerator(r::RationalFunction) -> Polynomial Return the numerator polynomial of `r`. See also: `den`. """ -num(r::RationalFunction) = r.num +numerator(r::RationalFunction) = r.num """ - den(r::RationalFunction) -> Poly + denominator(r::RationalFunction) -> Polynomial Return the denominator polynomial of `r`. See also: `num`. """ -den(r::RationalFunction) = r.den +denominator(r::RationalFunction) = r.den """ zeros(r::RationalFunction) -> Vector @@ -81,44 +81,44 @@ See also: `roots`, `zeros`, `solve`. poles(r::RationalFunction) = (rnew = reduce(r); roots(rnew.den)) ## Identities -one{T,S,U,V}(::Type{RationalFunction{Val{T},Val{S},U,V}}) = - RationalFunction(Poly([one(U)], T), Poly([one(V)], T), Val{S}) -one{T,S}(r::RationalFunction{T,S}) = +one(::Type{RationalFunction{Val{T},Val{S},U,V}}) where {T,S,U,V} = + RationalFunction(Polynomial([one(U)], T), Polynomial([one(V)], T), Val{S}) +one(r::RationalFunction{T,S}) where {T,S} = RationalFunction(one(r.num), one(r.den), S) -zero{T,S,U,V}(::Type{RationalFunction{Val{T},Val{S},U,V}}) = - RationalFunction(Poly(U[], T), Poly([one(V)], T), Val{S}) -zero{T,S}(r::RationalFunction{T,S}) = +zero(::Type{RationalFunction{Val{T},Val{S},U,V}}) where {T,S,U,V} = + RationalFunction(Polynomial(U[], T), Polynomial([one(V)], T), Val{S}) +zero(r::RationalFunction{T,S}) where {T,S} = RationalFunction(zero(r.num), one(r.den), S) ## Comparison -hash{T,S}(r::RationalFunction{Val{T},Val{S}}, h::UInt) = +hash(r::RationalFunction{Val{T},Val{S}}, h::UInt) where {T,S} = hash(T, hash(S, hash(coeffs(r.num), hash(coeffs(r.den), h)))) -=={T,S}(r1::RationalFunction{T,S}, r2::RationalFunction{T,S}) = +==(r1::RationalFunction{T,S}, r2::RationalFunction{T,S}) where {T,S} = r1.num * r2.den == r1.den * r2.num ==(r1::RationalFunction, r2::RationalFunction) = false -isequal{T,S}(r1::RationalFunction{T,S}, r2::RationalFunction{T,S}) = hash(r1) == hash(r2) +isequal(r1::RationalFunction{T,S}, r2::RationalFunction{T,S}) where {T,S} = + hash(r1) == hash(r2) isequal(r1::RationalFunction, r2::RationalFunction) = false # Auxiliary definitions for `isapprox` -eps{T<:AbstractFloat}(::Type{T}) = Base.eps(T) -eps{T<:AbstractFloat}(::Type{Complex{T}}) = Base.eps(T) -eps{T}(::Type{T}) = zero(T) +eps(::Type{T}) where {T<:AbstractFloat} = Base.eps(T) +eps(::Type{Complex{T}}) where {T<:AbstractFloat} = Base.eps(T) +eps(::Type{T}) where {T} = zero(T) -function isapprox{T,S,U1,V1,U2,V2}(r1::RationalFunction{Val{T},Val{S},U1,V1}, +function isapprox(r1::RationalFunction{Val{T},Val{S},U1,V1}, r2::RationalFunction{Val{T},Val{S},U2,V2}; - rtol::Real = sqrt(eps(promote_type(U1,V2,U2,V2))), atol::Real = 0) + rtol::Real = sqrt(eps(promote_type(U1,V2,U2,V2))), atol::Real = 0) where {T,S,U1,V1,U2,V2} p1 = r1.num * r2.den p2 = r1.den * r2.num isapprox(coeffs(p1), coeffs(p2); rtol = rtol, atol = atol) end -function isapprox{T1,S1,T2,S2}(r1::RationalFunction{Val{T1},Val{S1}}, - r2::RationalFunction{Val{T2},Val{S2}}; rtol::Real = 0, atol::Real = 0) - warn("r1≈r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables") - throw(DomainError()) +function isapprox(r1::RationalFunction{Val{T1},Val{S1}}, + r2::RationalFunction{Val{T2},Val{S2}}; rtol::Real = 0, atol::Real = 0) where {T1,S1,T2,S2} + throw(DomainError((r1,r2), "r1≈r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables")) end # Function evaluation @@ -132,8 +132,8 @@ function _funceval(r::RationalFunction, x::Number) den = r.den while isnan(result) && k ≤ mindegree # Apply L'Hospital - num = polyder(num) - den = polyder(den) + num = derivative(num) + den = derivative(den) result = num(x)/den(x) k += 1 end @@ -142,10 +142,10 @@ end _funceval(r::RationalFunction, X) = map(r, X) -@compat (r::RationalFunction)(x::Number) = _funceval(r, x) -@compat (r::RationalFunction{T,Val{:conj}}){T}(x::Number) = _funceval(r, conj(x)) -@compat (r::RationalFunction{T,Val{:conj}}){T}(x::Real) = _funceval(r, x) -@compat (r::RationalFunction)(X) = _funceval(r, X) +@compat (r::RationalFunction)(x::Number) = _funceval(r, x) +@compat (r::RationalFunction{T,Val{:conj}})(x::Number) where {T} = _funceval(r, conj(x)) +@compat (r::RationalFunction{T,Val{:conj}})(x::Real) where {T} = _funceval(r, x) +@compat (r::RationalFunction)(X) = _funceval(r, X) """ funcfit(x, y, m::Int, n::Int = 0, var = :x) -> RationalFunction @@ -165,14 +165,11 @@ where `n, r = divrem(length(x), 2)` and `m = n - 1 + r`. """ function funcfit(x, y, m::Int, n::Int, var::SymbolLike = :x) if length(x) ≠ length(y) - warn("funcfit(x, y, m, n, var): length(x) ≠ length(y)") - throw(DomainError()) + throw(DomainError((x,y,m,n,var), "funcfit(x, y, m, n, var): length(x) ≠ length(y)")) elseif m < 0 || n < 0 - warn("funcfit(x, y, m, n, var): `m` and `n` must be non-negative") - throw(DomainError()) + throw(DomainError((x,y,m,n,var), "funcfit(x, y, m, n, var): `m` and `n` must be non-negative")) elseif m + n + 1 > length(x) - warn("funcfit(x, y, m, n, var): not enough data points for given degrees") - throw(DomainError()) + throw(DomainError((x,y,m,n,var), "funcfit(x, y, m, n, var): not enough data points for given degrees")) end T = promote_type(eltype(x), eltype(y)) @@ -195,19 +192,19 @@ end # Mathematical operations (always return temporaries for correctness of the results) ## Inversion -inv{T,S}(r::RationalFunction{T,S}) = RationalFunction(copy(r.den), copy(r.num), S) +inv(r::RationalFunction{T,S}) where {T,S} = RationalFunction(copy(r.den), copy(r.num), S) ## Transposition transpose(r::RationalFunction) = copy(r) ## Conjugation -function conj{T,S}(r::RationalFunction{Val{T},Val{S}}) +function conj(r::RationalFunction{Val{T},Val{S}}) where {T,S} numcoeff, dencoeff = coeffs(r) - RationalFunction(Poly(conj(copy(numcoeff)), T), Poly(conj(copy(dencoeff)), T), + RationalFunction(Polynomial(conj(copy(numcoeff)), T), Polynomial(conj(copy(dencoeff)), T), Val{ifelse(S == :conj, :notc, :conj)}) end # Related to #2. This is the solution in Julia v0.6 in `arraymath.jl` -conj{T,S,U,V}(m::AbstractArray{RationalFunction{Val{T},Val{S},U,V}}) = map(conj, m) +conj(m::AbstractArray{RationalFunction{Val{T},Val{S},U,V}}) where {T,S,U,V} = map(conj, m) ## Derivative """ @@ -215,17 +212,16 @@ conj{T,S,U,V}(m::AbstractArray{RationalFunction{Val{T},Val{S},U,V}}) = map(conj, Take the `n`th order derivative of `r`. """ -function derivative{T,S}(r::RationalFunction{T,S}, n::Int = 1) +function derivative(r::RationalFunction{T,S}, n::Int = 1) where {T,S} if n < 0 - warn("derivative(r, n): `n` must be non-negative") - throw(DomainError()) + throw(DomainError((r, n),"derivative(r, n): `n` must be non-negative" )) end n == 0 && return copy(r) - num = polyder(r.num)*r.den - r.num*polyder(r.den) + num = derivative(r.num)*r.den - r.num*derivative(r.den) den = r.den*r.den temp = RationalFunction(num, den, S) for count in 2:n - num = polyder(temp.num)*temp.den - temp.num*polyder(temp.den) + num = derivative(temp.num)*temp.den - temp.num*derivative(temp.den) den = temp.den*temp.den temp = RationalFunction(num, den, S) end @@ -241,7 +237,7 @@ and denominator polynomials of `r`. See also: `zeros`, `poles`, `roots`. """ -function reduce{T,S}(r::RationalFunction{T,S}) +function reduce(r::RationalFunction{T,S}) where {T,S} g = gcd(r.num, r.den) common = degree(g) == 0 ? one(g) : g @@ -251,7 +247,7 @@ function reduce{T,S}(r::RationalFunction{T,S}) end ## Basic operations between rational functions -function +{T,S}(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) +function +(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) where {T,S} g = gcd(r1.den, r2.den) common = Polynomials.degree(g) == 0 ? one(g) : g @@ -262,149 +258,118 @@ function +{T,S}(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T} RationalFunction(num, den, Val{S}) end -function +{T1,S1,T2,S2}(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) - warn("r1+r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables") - throw(DomainError()) +function +(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) where {T1,S1,T2,S2} + throw(DomainError((r1, r2), "r1+r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables")) end -function *{T,S}(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) +function *(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) where {T,S} num = r1.num * r2.num den = r1.den * r2.den RationalFunction(num, den, Val{S}) end -function *{T1,S1,T2,S2}(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) - warn("r1*r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables") - throw(DomainError()) +function *(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) where {T1,S1,T2,S2} + throw(DomainError((r1, r2), "r1*r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables")) end dot(r1::RationalFunction, r2::RationalFunction) = *(r1, r2) -function /{T,S}(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) +^(r::RationalFunction, n::Integer) = Base.power_by_squaring(r,n) + +function /(r1::RationalFunction{Val{T},Val{S}}, r2::RationalFunction{Val{T},Val{S}}) where {T,S} num = r1.num * r2.den den = r1.den * r2.num RationalFunction(num, den, Val{S}) end -function /{T1,S1,T2,S2}(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) - warn("r1/r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables") - throw(DomainError()) +function /(r1::RationalFunction{Val{T1},Val{S1}}, r2::RationalFunction{Val{T2},Val{S2}}) where {T1,S1,T2,S2} + throw(DomainError((r1, r2), "r1/r2: `r1` ($T1,Val{$S1}) and `r2` ($T2,Val{$S2}) have different variables")) end --{T,S}(r::RationalFunction{T,S}) = RationalFunction(-r.num, copy(r.den), S) +-(r::RationalFunction{T,S}) where {T,S} = RationalFunction(-r.num, copy(r.den), S) -(r1::RationalFunction, r2::RationalFunction) = +(r1, -r2) -.+(r1::RationalFunction, r2::RationalFunction) = +(r1, r2) -.*(r1::RationalFunction, r2::RationalFunction) = *(r1, r2) -./(r1::RationalFunction, r2::RationalFunction) = /(r1, r2) -.-(r1::RationalFunction, r2::RationalFunction) = -(r1, r2) - ## Basic operations between `Number`s ==(r::RationalFunction, n::Number) = ==(r.num, n*r.den) ==(n::Number, r::RationalFunction) = ==(r, n) -isapprox{T,S,U,V,Z<:Number}(r::RationalFunction{T,S,U,V}, n::Z; - rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) = +isapprox(r::RationalFunction{T,S,U,V}, n::Z; + rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) where {T,S,U,V,Z<:Number} = isapprox(coeffs(r.num), coeffs(n*r.den); rtol = rtol, atol = atol) -isapprox{T,S,U,V,Z<:Number}(n::Z, r::RationalFunction{T,S,U,V}; - rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) = +isapprox(n::Z, r::RationalFunction{T,S,U,V}; + rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) where {T,S,U,V,Z<:Number} = isapprox(r, n; rtol = rtol, atol = atol) -+{T,S}(r::RationalFunction{T,S}, n::Number) = RationalFunction(r.num + n*r.den, copy(r.den), S) -+(n::Number, r::RationalFunction) = +(r, n) -*{T,S}(r::RationalFunction{T,S}, n::Number) = RationalFunction(n*r.num, copy(r.den), S) -*(n::Number, r::RationalFunction) = *(r, n) -dot(r::RationalFunction, n::Number) = *(r, n) -dot(n::Number, r::RationalFunction) = *(r, n) -/{T,S}(r::RationalFunction{T,S}, n::Number) = RationalFunction(copy(r.num), n*r.den, S) -/{T,S}(n::Number, r::RationalFunction{T,S}) = RationalFunction(n*r.den, copy(r.num), S) --(r::RationalFunction, n::Number) = +(r, -n) --(n::Number, r::RationalFunction) = +(-r, n) - -.+(r::RationalFunction, n::Number) = +(r, n) -.*(r::RationalFunction, n::Number) = *(r, n) -./(r::RationalFunction, n::Number) = /(r, n) -.-(r::RationalFunction, n::Number) = +(r, -n) - -.+(n::Number, r::RationalFunction) = +(r, n) -.*(n::Number, r::RationalFunction) = *(r, n) -./(n::Number, r::RationalFunction) = /(n, r) -.-(n::Number, r::RationalFunction) = +(-r, n) - -## Basic operations between `Poly`s -function =={T,S}(r::RationalFunction{Val{T},S}, p::Poly) ++(r::RationalFunction{T,S}, n::Number) where {T,S} = RationalFunction(r.num + n*r.den, copy(r.den), S) ++(n::Number, r::RationalFunction) = +(r, n) +*(r::RationalFunction{T,S}, n::Number) where {T,S} = RationalFunction(n*r.num, copy(r.den), S) +*(n::Number, r::RationalFunction) = *(r, n) +dot(r::RationalFunction, n::Number) = *(r, n) +dot(n::Number, r::RationalFunction) = *(r, n) +/(r::RationalFunction{T,S}, n::Number) where {T,S} = RationalFunction(copy(r.num), n*r.den, S) +/(n::Number, r::RationalFunction{T,S}) where {T,S} = RationalFunction(n*r.den, copy(r.num), S) +-(r::RationalFunction, n::Number) = +(r, -n) +-(n::Number, r::RationalFunction) = +(-r, n) + +## Basic operations between `Polynomial`s +function ==(r::RationalFunction{Val{T},S}, p::Polynomial) where {T,S} T ≠ p.var && return false return r.num == p*r.den end -==(p::Poly, r::RationalFunction) = ==(r, p) +==(p::Polynomial, r::RationalFunction) = ==(r, p) -function isapprox{T,S,U,V,Z<:Number}(r::RationalFunction{Val{T},S,U,V}, p::Poly{Z}; - rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) +function isapprox(r::RationalFunction{Val{T},S,U,V}, p::Polynomial{Z}; + rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) where {T,S,U,V,Z<:Number} if T ≠ p.var - warn("r≈p: `r` ($T) and `p` ($(p.var)) have different variables") - throw(DomainError()) + throw(DomainError((r,p), "r≈p: `r` ($T) and `p` ($(p.var)) have different variables")) end isapprox(coeffs(r.num), coeffs(p*r.den); rtol = rtol, atol = atol) end -isapprox{T,S,U,V,Z<:Number}(p::Poly{Z}, r::RationalFunction{Val{T},S,U,V}; - rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) = +isapprox(p::Polynomial{Z}, r::RationalFunction{Val{T},S,U,V}; + rtol::Real = sqrt(eps(promote_type(U,V,Z))), atol::Real = 0) where {T,S,U,V,Z<:Number} = isapprox(r, p; rtol = rtol, atol = atol) -function +{T,S}(r::RationalFunction{Val{T},S}, p::Poly) +function +(r::RationalFunction{Val{T},S}, p::Polynomial) where {T,S} if T ≠ p.var - warn("r+p: `r` ($T) and `p` ($(p.var)) have different variables") - throw(DomainError()) + throw(DomainError((r,p), "r+p: `r` ($T) and `p` ($(p.var)) have different variables")) end RationalFunction(r.num + p*r.den, r.den, S) end -+(p::Poly, r::RationalFunction) = +(r, p) ++(p::Polynomial, r::RationalFunction) = +(r, p) -function *{T,S}(r::RationalFunction{Val{T},S}, p::Poly) +function *(r::RationalFunction{Val{T},S}, p::Polynomial) where {T,S} if T ≠ p.var - warn("r*p: `r` ($T) and `p` ($(p.var)) have different variables") - throw(DomainError()) + throw(DomainError((r,p), "r*p: `r` ($T) and `p` ($(p.var)) have different variables")) end RationalFunction(p*r.num, r.den, S) end -*(p::Poly, r::RationalFunction) = *(r, p) -dot(r::RationalFunction, p::Poly) = *(r, p) -dot(p::Poly, r::RationalFunction) = *(r, p) +*(p::Polynomial, r::RationalFunction) = *(r, p) +dot(r::RationalFunction, p::Polynomial) = *(r, p) +dot(p::Polynomial, r::RationalFunction) = *(r, p) -function /{T,S}(r::RationalFunction{Val{T},S}, p::Poly) +function /(r::RationalFunction{Val{T},S}, p::Polynomial) where {T,S} if T ≠ p.var - warn("r/p: `r` ($T) and `p` ($(p.var)) have different variables") - throw(DomainError()) + throw(DomainError((r,p), "r/p: `r` ($T) and `p` ($(p.var)) have different variables")) end RationalFunction(r.num, p*r.den, S) end -function /{T,S}(p::Poly, r::RationalFunction{Val{T},S}) +function /(p::Polynomial, r::RationalFunction{Val{T},S}) where {T,S} if T ≠ p.var - warn("p/r: `p` ($(p.var)) and `r` ($T) have different variables") - throw(DomainError()) + throw(DomainError((r,p), "p/r: `p` ($(p.var)) and `r` ($T) have different variables")) end RationalFunction(p*r.den, r.num, S) end --(r::RationalFunction, p::Poly) = +(r, -p) --(p::Poly, r::RationalFunction) = +(-r, p) - -.+(r::RationalFunction, p::Poly) = +(r, p) -.*(r::RationalFunction, p::Poly) = *(r, p) -./(r::RationalFunction, p::Poly) = /(r, p) -.-(r::RationalFunction, p::Poly) = +(r, -p) - -.+(p::Poly, r::RationalFunction) = +(r, p) -.*(p::Poly, r::RationalFunction) = *(r, p) -./(p::Poly, r::RationalFunction) = /(p, r) -.-(p::Poly, r::RationalFunction) = +(-r, p) +-(r::RationalFunction, p::Polynomial) = +(r, -p) +-(p::Polynomial, r::RationalFunction) = +(-r, p) ## Solve """ solve(lhs, rhs = 0) -> Vector Solve for the values which make `lhs = rhs`, where at least one of `lhs` and `rhs` -is a `RationalFunction` while the other can be either a `Number` or a `Poly`. +is a `RationalFunction` while the other can be either a `Number` or a `Polynomial`. See also: `zeros`, `poles`, `roots`. """ @@ -415,24 +380,23 @@ function solve(lhs::RationalFunction, rhs::Number = 0) zeros(lhs - rhs) end -function solve(lhs::RationalFunction, rhs::Poly) +function solve(lhs::RationalFunction, rhs::Polynomial) lhs == rhs && error("solve(lhs,rhs): `lhs` and `rhs` are equal") rhs == zero(rhs) && return zeros(lhs) zeros(lhs - rhs) end -solve(lhs::PolyLike, rhs::RationalFunction) = solve(rhs, lhs) +solve(lhs::PolynomialLike, rhs::RationalFunction) = solve(rhs, lhs) -function solve{T,S}(lhs::RationalFunction{Val{T},Val{S}}, - rhs::RationalFunction{Val{T},Val{S}}) +function solve(lhs::RationalFunction{Val{T},Val{S}}, + rhs::RationalFunction{Val{T},Val{S}}) where {T,S} lhs == rhs && error("solve(lhs,rhs): `lhs` and `rhs` are equal") zeros(lhs - rhs) end -function solve{T1,S1,T2,S2}(lhs::RationalFunction{Val{T1},Val{S1}}, - rhs::RationalFunction{Val{T2},Val{S2}}) - warn("solve(lhs,rhs): `lhs` ($T1,Val{$S1}) and `rhs` ($T2,Val{$S2}) have different variables") - throw(DomainError()) +function solve(lhs::RationalFunction{Val{T1},Val{S1}}, + rhs::RationalFunction{Val{T2},Val{S2}}) where {T1,S1,T2,S2} + throw(DomainError((lhs,rhs), "solve(lhs,rhs): `lhs` ($T1,Val{$S1}) and `rhs` ($T2,Val{$S2}) have different variables")) end ### Given rational function, return partial fraction decomposition @@ -443,7 +407,7 @@ end Given a numerator and denominator of a polynomial fraction or a RationalFunction, return the partial fraction decomposition. The residues are returned as `r`, the poles as `p`, and the direct terms as `k`. Both numerator and denominator can be -given as an array of coefficients or as Poly types. +given as an array of coefficients or as Polynomial types. Duplicate poles are handled by each subsequent duplicate having the denominator's power raised by one. See package README for further explanation. @@ -451,8 +415,8 @@ denominator's power raised by one. See package README for further explanation. # Examples ``` julia # Real poles with direct terms -julia> num1 = Poly([6, 9, 16, 8, 1]) -julia> den1 = Poly([6, 11, 6, 1]) +julia> num1 = Polynomial([6, 9, 16, 8, 1]) +julia> den1 = Polynomial([6, 11, 6, 1]) julia> residue(num1, den1) ([-6.0, -4.0, 3.0], [-3.0, -2.0, -1.0], [2.0, 1.0]) @@ -461,12 +425,12 @@ julia> residue([10, 2], [0, 10, 2, 1]) (Complex{Float64}[-0.5-0.166667im, -0.5+0.166667im, 1.0+0.0im], Complex{Float64}[-1.0+3.0im, -1.0-3.0im, 0.0+0.0im], [0.0]) # Duplicate poles -julia> r_func = RationalFunction(Poly([1,0,1]),Poly([0,1])*Poly([-1,1])^2)) +julia> r_func = RationalFunction(Polynomial([1,0,1]),Polynomial([0,1])*Polynomial([-1,1])^2)) julia> residue(r_func) ([-0.0, 2.0, 1.0], [1.0, 1.0, 0.0], [0.0]) ``` """ -function residue(num::Poly, den::Poly) +function residue(num::Polynomial, den::Polynomial) p = roots(den) num_p = length(p) div_poly, rem_poly = divrem(num, den) @@ -499,14 +463,14 @@ function residue(num::Poly, den::Poly) for col_idx in 1:num_p temp_p = p[col_idx] if temp_p in keys(dup_p_dict) - temp_poly = Poly([-temp_p, 1])^dup_p_dict[temp_p] + temp_poly = Polynomial([-temp_p, 1])^dup_p_dict[temp_p] dup_p_dict[temp_p]-=1 else - temp_poly = Poly(1) + temp_poly = Polynomial(1) end for poly_idx in 1:num_p if p[poly_idx] != temp_p - temp_poly *= Poly([-p[poly_idx], 1]) + temp_poly *= Polynomial([-p[poly_idx], 1]) end end temp_coeffs = coeffs(temp_poly) @@ -517,8 +481,8 @@ function residue(num::Poly, den::Poly) r = residue_mtx\rem_coeffs return r, p, k end -residue{T<:Number}(num::Vector{T}, den::Vector{T}) = residue(Poly(num), Poly(den)) -residue(rfunc::RationalFunction) = residue(num(rfunc), den(rfunc)) +residue(num::Vector{T}, den::Vector{T}) where {T<:Number} = residue(Polynomial(num), Polynomial(den)) +residue(rfunc::RationalFunction) = residue(numerator(rfunc), denominator(rfunc)) ### Conversely, given r, p, and k terms, return polynomial fraction """ @@ -553,8 +517,8 @@ julia> residue(r, p, k) ([1.0, 0.0, 1.0], [0.0, 1.0, -2.0, 1.0]) ``` """ -function residue{T<:Number,S<:Number,U<:Number}(r::Vector{T}, p::Vector{S}, k::Vector{U}) - den_poly = poly(p) +function residue(r::Vector{T}, p::Vector{S}, k::Vector{U}) where {T<:Number,S<:Number,U<:Number} + den_poly = fromroots(p) unique_p = unique(p) dup_p_dict = Dict() p_count_dict = Dict() @@ -565,21 +529,21 @@ function residue{T<:Number,S<:Number,U<:Number}(r::Vector{T}, p::Vector{S}, k::V dup_p_dict[pole] = temp_count-1 end end - r_poly = Poly(0) + r_poly = Polynomial(0) for resid_idx in 1:length(r) - temp_num_term = Poly(1) + temp_num_term = Polynomial(1) if p[resid_idx] in keys(dup_p_dict) - temp_num_term *= Poly([-p[resid_idx],1])^dup_p_dict[p[resid_idx]] + temp_num_term *= Polynomial([-p[resid_idx],1])^dup_p_dict[p[resid_idx]] dup_p_dict[p[resid_idx]]-=1 end for pole in keys(p_count_dict) if pole != p[resid_idx] - temp_num_term *= Poly([-pole, 1])^p_count_dict[pole] + temp_num_term *= Polynomial([-pole, 1])^p_count_dict[pole] end end r_poly += temp_num_term*r[resid_idx] end - k_poly = Poly(k)*den_poly + k_poly = Polynomial(k)*den_poly num_poly = k_poly+r_poly return coeffs(num_poly), coeffs(den_poly) end diff --git a/src/plotting.jl b/src/plotting.jl index b8544f7..dd1ea16 100644 --- a/src/plotting.jl +++ b/src/plotting.jl @@ -1,8 +1,7 @@ @recipe function f{T,S,U<:Real,V<:Real,W<:Real,Z<:Real}(r::RationalFunction{Val{T},Val{S},U,V}, x::AbstractVector, xinit::AbstractVector{W}, yinit::AbstractVector{Z}) if length(xinit) ≠ length(yinit) - warn("plot(r, x, xinit, yinit): length(xinit) ≠ length(yinit)") - throw(DomainError()) + throw(DomainError((r, x, xinit, yinit), "plot(r, x, xinit, yinit): length(xinit) ≠ length(yinit)")) end # Some defaults diff --git a/src/printing.jl b/src/printing.jl index 7146af7..16c99e3 100644 --- a/src/printing.jl +++ b/src/printing.jl @@ -1,13 +1,13 @@ -summary{T,S,U,V}(::RationalFunction{Val{T},Val{S},U,V}) = "RF{Val{$T},Val{$S},$U,$V}" +summary(::RationalFunction{Val{T},Val{S},U,V}) where {T,S,U,V} = "RF{Val{$T},Val{$S},$U,$V}" # Compact representations -function _compact{T,S}(stream, ::MIME"text/plain", r::RationalFunction{Val{T},Val{S}}) +function _compact(stream, ::MIME"text/plain", r::RationalFunction{Val{T},Val{S}}) where {T,S} var = ifelse(S == :conj, "$(T)̄", "$(T)") # print(stream, "num($(var))/den($(var))") print(stream, "n($(var))/d($(var))") end -function _compact{T,S}(stream, ::MIME"text/latex", r::RationalFunction{Val{T},Val{S}}) +function _compact(stream, ::MIME"text/latex", r::RationalFunction{Val{T},Val{S}}) where {T,S} var = ifelse(S == :conj, "\\bar{$(T)}", "$(T)") print(stream, "\$") # print(stream, "\\tfrac{\\mathrm{num}($(var))}{\\mathrm{den}($(var))}") @@ -18,7 +18,7 @@ end # TODO: Think about text/html # Full representations -function _full{T,S}(stream, m::MIME"text/plain", r::RationalFunction{Val{T},Val{S}}) +function _full(stream, m::MIME"text/plain", r::RationalFunction{Val{T},Val{S}}) where {T,S} var = ifelse(S == :conj, "$(T)̄", "$(T)") println(stream, "f($(var)) = num($(var))/den($(var)), where,") print(stream, "num($(T)) is ") @@ -29,7 +29,7 @@ function _full{T,S}(stream, m::MIME"text/plain", r::RationalFunction{Val{T},Val{ print(stream, ".") end -function _full{T,S}(stream, m::MIME"text/latex", r::RationalFunction{Val{T},Val{S}}) +function _full(stream, m::MIME"text/latex", r::RationalFunction{Val{T},Val{S}}) where {T,S} var = ifelse(S == :conj, "\\bar{$(T)}", "$(T)") print(stream, "\$\$") print(stream, "f($(var)) = \\frac{\\mathrm{num}($(var))}{\\mathrm{den}($(var))}\\,,") diff --git a/src/type.jl b/src/type.jl index 08472fd..12651fb 100644 --- a/src/type.jl +++ b/src/type.jl @@ -3,26 +3,26 @@ """ Alias for `Symbol`-like types: `AbstractString`, `Char`, `Symbol`. -See also: `RationalFunctions.PolyLike`. +See also: `RationalFunctions.PolynomialLike`. """ const SymbolLike = Union{AbstractString,Char,Symbol} """ -Alias for `Poly`-like types: `Number`, `Poly`. +Alias for `Polynomial-like types: `Number`, `Polynomial`. See also: `RationalFunctions.SymbolLike`. """ -const PolyLike = Union{Number,Poly} +const PolynomialLike = Union{Number,Polynomial} """ Constructor for `RationalFunction` objects. -Construct `RationalFunction` objects from `Poly` objects: +Construct `RationalFunction` objects from `Polynomial` objects: RationalFunction(num, den = one(num), conj = Val{:notc}) where, - * at least one of `num` and `den` objects is `Poly`, while the other can be either + * at least one of `num` and `den` objects is `Polynomial`, while the other can be either a `Number` or a `Vector`, and, * `conj` is a type which indicates whether the variable will be conjugated (`Val{:conj}`) in function evaluations, or not (`Val{:notc}`). @@ -38,96 +38,92 @@ where, # Examples ```julia julia> r1 = RationalFunction(poly([1,2,3])); -julia> r2 = RationalFunction(poly([1,2,3]), Poly([1,2,3])); +julia> r2 = RationalFunction(poly([1,2,3]), Polynomial([1,2,3])); julia> r3 = RationalFunction(poly([1,2,3]), RationalFunctions.Val{:conj}); julia> r4 = RationalFunction([1,2,3]); julia> r5 = RationalFunction(1, [1, 2, 3], "s"); julia> r6 = RationalFunction([1,2,3], 't', RationalFunctions.Val{:conj}); ``` -See also: `RationalFunctions.SymbolLike`, `RationalFunctions.PolyLike`, `coeffs`, +See also: `RationalFunctions.SymbolLike`, `RationalFunctions.PolynomialLike`, `coeffs`, `degree`, `roots`, `variable`, `num`, `den`, `zeros`, `poles`, `funcfit`, `derivative`, `reduce`, `solve`. """ -immutable RationalFunction{T,S,U,V} - num::Poly{U} - den::Poly{V} +struct RationalFunction{T,S,U,V} + num::Polynomial{U} + den::Polynomial{V} # Full construction (from numerator and denominator polynomials) - @compat function (::Type{RationalFunction}){U<:Number,V<:Number}(num::Poly{U}, - den::Poly{V}, ::Type{Val{:conj}}) + @compat function (::Type{RationalFunction})(num::Polynomial{U}, den::Polynomial{V}, + ::Type{Val{:conj}}) where {U<:Number,V<:Number} if num.var ≠ den.var - warn("RationalFunction(num,den): num and den `Poly`s have different variables") - throw(DomainError()) + throw(DomainError((num, den), "RationalFunction(num,den): num and den `Polynomial`s have different variables")) end new{Val{num.var},Val{:conj},U,V}(num,den) end - @compat function (::Type{RationalFunction}){U<:Number,V<:Number}(num::Poly{U}, - den::Poly{V}, ::Type{Val{:notc}}) + @compat function (::Type{RationalFunction})(num::Polynomial{U}, den::Polynomial{V}, + ::Type{Val{:notc}}) where {U<:Number,V<:Number} if num.var ≠ den.var - warn("RationalFunction(num,den): num and den `Poly`s have different variables") - throw(DomainError()) + throw(DomainError((num, den), "RationalFunction(num,den): num and den `Polynomial`s have different variables")) end new{Val{num.var},Val{:notc},U,V}(num,den) end - @compat function (::Type{RationalFunction}){U<:Number,V<:Number}(num::Poly{U}, - den::Poly{V}) + @compat function (::Type{RationalFunction})(num::Polynomial{U}, den::Polynomial{V}) where + {U<:Number,V<:Number} if num.var ≠ den.var - warn("RationalFunction(num,den): num and den `Poly`s have different variables") - throw(DomainError()) + throw(DomainError((num, den), "RationalFunction(num,den): num and den `Polynomial`s have different variables")) end new{Val{num.var},Val{:notc},U,V}(num,den) end end -# Partial construction from `Poly`s -RationalFunction{S}(num::Poly, conj::Type{Val{S}} = Val{:notc}) = +# Partial construction from `Polynomial`s +RationalFunction(num::Polynomial, conj::Type{Val{S}} = Val{:notc}) where {S} = RationalFunction(num, one(num), conj) -# Full construction from `Number`s, `Vector`s and `Poly`s -RationalFunction{S}(num::Number, den::Poly, conj::Type{Val{S}} = Val{:notc}) = - RationalFunction(Poly([num], den.var), den, conj) +# Full construction from `Number`s, `Vector`s and `Polynomial`s +RationalFunction(num::Number, den::Polynomial, conj::Type{Val{S}} = Val{:notc}) where {S} = + RationalFunction(Polynomial([num], den.var), den, conj) -RationalFunction{S}(num::Poly, den::Number, conj::Type{Val{S}} = Val{:notc}) = - RationalFunction(num, Poly([den], num.var), conj) +RationalFunction(num::Polynomial, den::Number, conj::Type{Val{S}} = Val{:notc}) where {S} = + RationalFunction(num, Polynomial([den], num.var), conj) -RationalFunction{S}(num::Vector, den::Poly, conj::Type{Val{S}} = Val{:notc}) = - RationalFunction(Poly(num, den.var), den, conj) +RationalFunction(num::Vector, den::Polynomial, conj::Type{Val{S}} = Val{:notc}) where {S} = + RationalFunction(Polynomial(num, den.var), den, conj) -RationalFunction{S}(num::Poly, den::Vector, conj::Type{Val{S}} = Val{:notc}) = - RationalFunction(num, Poly(den, num.var), conj) +RationalFunction(num::Polynomial, den::Vector, conj::Type{Val{S}} = Val{:notc}) where {S} = + RationalFunction(num, Polynomial(den, num.var), conj) # Full construction from numbers and vectors -RationalFunction{S}(num::Vector, den::Vector, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly(num, var), Poly(den, var), conj) +RationalFunction(num::Vector, den::Vector, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S} = RationalFunction(Polynomial(num, var), Polynomial(den, var), conj) -RationalFunction{S}(num::Number, den::Number, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly([num], var), Poly([den], var), conj) +RationalFunction(num::Number, den::Number, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S} = RationalFunction(Polynomial([num], var), Polynomial([den], var), conj) -RationalFunction{S}(num::Vector, den::Number, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly(num, var), Poly([den], var), conj) +RationalFunction(num::Vector, den::Number, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S} = RationalFunction(Polynomial(num, var), Polynomial([den], var), conj) -RationalFunction{S}(num::Number, den::Vector, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly([num], var), Poly(den, var), conj) +RationalFunction(num::Number, den::Vector, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S} = RationalFunction(Polynomial([num], var), Polynomial(den, var), conj) # Partial construction from numbers and vectors -RationalFunction{S,U<:Number}(num::Vector{U}, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly(num, var), - Poly([one(U)], var), conj) +RationalFunction(num::Vector{U}, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S,U<:Number} = RationalFunction(Polynomial(num, var), + Polynomial([one(U)], var), conj) -RationalFunction{S,U<:Number}(num::U, var::SymbolLike = :x, - conj::Type{Val{S}} = Val{:notc}) = RationalFunction(Poly([num], var), - Poly([one(U)], var), conj) +RationalFunction(num::U, var::SymbolLike = :x, + conj::Type{Val{S}} = Val{:notc}) where {S,U<:Number} = RationalFunction(Polynomial([num], var), + Polynomial([one(U)], var), conj) """ - Poly(r::RationalFunction) + Polynomial(r::RationalFunction) -Create a `Poly` object from `r` if `degree(den(r)) == 0`. +Create a `Polynomial` object from `r` if `degree(den(r)) == 0`. """ -function Poly(r::RationalFunction) +function Polynomial(r::RationalFunction) if degree(r.den) ≠ 0 - warn("Poly(r): r.den is not constant") - throw(DomainError()) + throw(DomainError(r.den, "Polynomial(r): r.den is not constant")) end r.num / r.den[0] end diff --git a/test/runtests.jl b/test/runtests.jl index 3c4f98e..c2a0fcf 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,14 +2,15 @@ using Plots gr(display = false) using Polynomials +using LinearAlgebra using RationalFunctions -using Base.Test +using Test # Constructor tests ## Construction from polynomials -px_ = Poly([1,-2,1]) # px_ = (x-1)(x-1) -qx = poly([1,2,3]) # qx = (x-1)(x-2)(x-3) -ps = Poly([1,-2,1], :s) # ps = (s-1)(s-1) +px_ = Polynomial([1,-2,1]) # px_ = (x-1)(x-1) +qx = fromroots([1,2,3]) # qx = (x-1)(x-2)(x-3) +ps = Polynomial([1,-2,1], :s) # ps = (s-1)(s-1) @test isequal(RationalFunction(px_, qx), RationalFunction(px_, qx, Val{:notc})) @test isa(RationalFunction(px_, qx, Val{:conj}), RationalFunction{Val{px_.var}, Val{:conj}, eltype(px_), eltype(qx)}) @@ -20,7 +21,7 @@ ps = Poly([1,-2,1], :s) # ps = (s-1)(s-1) @test_throws DomainError RationalFunction(px_, ps, Val{:conj}) @test isequal(RationalFunction(coeffs(px_), qx), RationalFunction(px_, coeffs(qx))) -@test isequal(RationalFunction(1, Poly([2])), RationalFunction(Poly([1]), 2)) +@test isequal(RationalFunction(1, Polynomial([2])), RationalFunction(Polynomial([1]), 2)) ## Construction from numbers and vectors @test isequal(RationalFunction(1, [1, 2]), RationalFunction([1], [1, 2])) @@ -29,18 +30,18 @@ ps = Poly([1,-2,1], :s) # ps = (s-1)(s-1) @test isa(RationalFunction(1), RationalFunction{Val{:x}, Val{:notc}, Int, Int}) @test isa(RationalFunction([1, 2.], 's', Val{:conj}), RationalFunction{Val{:s}, Val{:conj}, Float64, Float64}) -## `Poly` construction from `RationalFunction`s +## `Polynomial` construction from `RationalFunction`s r1 = RationalFunction(px_, qx) -r2 = RationalFunction(px_, Poly([4])) +r2 = RationalFunction(px_, Polynomial([4])) -@test isapprox(coeffs(Poly(r2)), coeffs(px_/4)) -@test_throws DomainError Poly(r1) +@test isapprox(coeffs(Polynomial(r2)), coeffs(px_/4)) +@test_throws DomainError Polynomial(r1) # Conversion tests v1 = [1, 2, 3] v2 = [1., 2., 3.] v3 = [1 + 1im, 2. - 1im] -p3 = poly(v3) +p3 = fromroots(v3) @test eltype([RationalFunction(v1, v2), RationalFunction(v2, v1)]) == RationalFunction{Val{:x}, Val{:notc}, promote_type(eltype(v1), eltype(v2)), promote_type(eltype(v1), eltype(v2))} @@ -81,8 +82,8 @@ r3 = RationalFunction([-0., 1, 2], :x) @test r1 == r3 && r1 ≈ r3 && !isequal(r1, r3) ## Function evaluation -p1 = Poly([1,-2,1]) # p1 = (x-1)(x-1) -p2 = poly([1,2,3]) # p2 = (x-1)(x-2)(x-3) +p1 = Polynomial([1,-2,1]) # p1 = (x-1)(x-1) +p2 = fromroots([1,2,3]) # p2 = (x-1)(x-2)(x-3) r1 = RationalFunction(p1, p2) r2 = conj(r1) @@ -90,23 +91,23 @@ r2 = conj(r1) realinput = [1., 2., 3., 4., 5.] imaginput = realinput + [0.1, -0.2, 0.3, -0.4, 0.5]*1im -@test_approx_eq(r1(realinput), r2(realinput)) -@test_approx_eq(r1(imaginput), conj(r2(imaginput))) +@test r1(realinput) ≈ r2(realinput) +@test r1(imaginput) ≈ conj(r2(imaginput)) r1 = RationalFunction(3p1, 5p1) r2 = RationalFunction(3p1, 5p2) r3 = RationalFunction(3p2, 5p1) -@test_approx_eq(r1(1), 3/5) -@test_approx_eq(r2(1), 0) -@test_approx_eq(r3(1), Inf) +@test r1(1) ≈ 3/5 +@test r2(1) ≈ 0 +@test r3(1) ≈ Inf -@test_approx_eq(r1(realinput), fill(3/5, size(realinput))) -@test_approx_eq(r1(imaginput), fill(3/5, size(realinput))) +@test r1(realinput) ≈ fill(3/5, size(realinput)) +@test r1(imaginput) ≈ fill(3/5, size(realinput)) -@test_approx_eq(r1(Inf), 3/5) -@test_approx_eq(r2(Inf), 0) -@test_approx_eq(r3(Inf), Inf) +@test r1(Inf) ≈ 3/5 +@test r2(Inf) ≈ 0 +@test r3(Inf) ≈ Inf ## Function fitting x = -2:1E-1:2 @@ -138,8 +139,8 @@ r3 = transpose(r1) r1 = RationalFunction([1+1im, 2.], [1-3im, 5, 8im]) r2 = conj(r1) -@test num(r1) == conj(num(r2)) -@test den(r1) == conj(den(r2)) +@test numerator(r1) == conj(numerator(r2)) +@test denominator(r1) == conj(denominator(r2)) # test related to #2 m1 = fill(r1,1,1) # [r1] @@ -157,11 +158,11 @@ r4 = convert(typeof(r2), r1) ## Derivative and reduction ### p1 = (x-1)(x-1) ### p2 = (x-1)(x-2)(x-3) -p3 = poly([1]) # p3 = (x-1) -p4 = poly([2,3]) # p4 = (x-2)(x-3) +p3 = fromroots([1]) # p3 = (x-1) +p4 = fromroots([2,3]) # p4 = (x-2)(x-3) r1 = RationalFunction(p1, p2) -result = RationalFunction(polyder(p3)*p4 - p3*polyder(p4), p4^2) +result = RationalFunction(derivative(p3)*p4 - p3*derivative(p4), p4^2) @test derivative(r1) == result @test !isequal(derivative(r1), result) @@ -170,7 +171,7 @@ result = RationalFunction(polyder(p3)*p4 - p3*polyder(p4), p4^2) r1 = RationalFunction(p1, p1) @test derivative(r1, 0) == r1 @test derivative(r1) == 0 -@test derivative(RationalFunction(1, p3), 2) == RationalFunction(2, poly([1; 1; 1])) +@test derivative(RationalFunction(1, p3), 2) == RationalFunction(2, fromroots([1; 1; 1])) @test_throws DomainError derivative(r1, -1) ## Mathematical operations @@ -179,18 +180,18 @@ r1 = RationalFunction(1, [-1, 1], :x) # r1 = 1/(x-1) r2 = RationalFunction(-1, [1, 1], :x) # r2 = -1/(x+1) r3 = RationalFunction(1, [-1, 1], :s) # r3 = 1/(s-1) -for op in (:+, :-, :*, :/, :dot, :.+, :.-, :.*, :./) +for op in (:+, :-, :*, :/, :dot) @test_throws DomainError eval( :(($op)(r1, r3)) ) end -@test r1+r2 ≈ r1 .+ r2 ≈ RationalFunction( 2 , [-1, 0, 1]) -@test r1-r2 ≈ r1 .- r2 ≈ RationalFunction([0, 2], [-1, 0, 1]) -@test r1*r2 ≈ r1 .* r2 ≈ dot(r1, r2) ≈ RationalFunction(-1, [-1, 0, 1]) -@test r1/r2 ≈ r1 ./ r2 ≈ inv(r2/r1) ≈ -RationalFunction([1, 1], [-1, 1]) +@test r1+r2 ≈ RationalFunction( 2 , [-1, 0, 1]) +@test r1-r2 ≈ RationalFunction([0, 2], [-1, 0, 1]) +@test r1*r2 ≈ dot(r1, r2) ≈ RationalFunction(-1, [-1, 0, 1]) +@test r1/r2 ≈ inv(r2/r1) ≈ -RationalFunction([1, 1], [-1, 1]) ### Between polynomials -p1 = Poly([1, 1], :x) # p1 = (x+1) -p2 = Poly([1, 1], :s) # p2 = (s+1) +p1 = Polynomial([1, 1], :x) # p1 = (x+1) +p2 = Polynomial([1, 1], :s) # p2 = (s+1) r1 = RationalFunction(p1) # r1 = (x+1)/1 @test p1 == r1 == p1 @@ -202,15 +203,15 @@ r1 = RationalFunction(p1) # r1 = (x+1)/1 r1 = RationalFunction([0, 1, 1], [-1, 1], :x) # r1 = x(x+1)/(x-1) -for op in (:+, :-, :*, :/, :dot, :.+, :.-, :.*, :./) +for op in (:+, :-, :*, :/, :dot) @test_throws DomainError eval( :(($op)(r1, p2)) ) @test_throws DomainError eval( :(($op)(p2, r1))) end -@test p1+r1 ≈ p1 .+ r1 ≈ r1+p1 ≈ r1 .+ p1 ≈ RationalFunction([-1, 1, 2], [-1, 1]) -@test r1-p1 ≈ r1 .- p1 ≈ -(p1-r1) ≈ -(p1 .- r1) ≈ RationalFunction([1, 1],[-1, 1]) -@test r1*p1 ≈ r1 .* p1 ≈ dot(r1, p1) ≈ p1*r1 ≈ p1 .* r1 ≈ dot(p1, r1) ≈ RationalFunction([0, 1, 2, 1], [-1, 1]) -@test r1/p1 ≈ r1 ./ p1 ≈ inv(p1/r1) ≈ inv(p1 ./ r1) ≈ RationalFunction([0, 1], [-1, 1]) +@test p1+r1 ≈ r1+p1 ≈ RationalFunction([-1, 1, 2], [-1, 1]) +@test r1-p1 ≈ -(p1-r1) ≈ RationalFunction([1, 1],[-1, 1]) +@test r1*p1 ≈ dot(r1, p1) ≈ p1*r1 ≈ dot(p1, r1) ≈ RationalFunction([0, 1, 2, 1], [-1, 1]) +@test r1/p1 ≈ inv(p1/r1) ≈ RationalFunction([0, 1], [-1, 1]) ### Between numbers n = 3. @@ -224,10 +225,10 @@ r1 = RationalFunction(n*[1, 1], [1, 1]) r1 = RationalFunction([-1, 1], [1, 1]) # r1 = (x-1)/(x+1) -@test r1+n ≈ r1 .+ n ≈ n+r1 ≈ n .+ r1 ≈ RationalFunction([2, 4], [1, 1]) -@test r1-n ≈ r1 .- n ≈ -(n-r1) ≈ -(n .- r1) ≈ RationalFunction([-4, -2], [1, 1]) -@test r1*n ≈ r1 .* n ≈ dot(r1, n) ≈ n*r1 ≈ n .* r1 ≈ dot(n, r1) ≈ RationalFunction([-3, 3], [1, 1]) -@test r1/n ≈ r1 ./ n ≈ inv(n/r1) ≈ inv(n ./ r1) ≈ RationalFunction([-1, 1], [3, 3]) ≈ RationalFunction([-1, 1]/3, [1, 1]) +@test r1+n ≈ n+r1 ≈ RationalFunction([2, 4], [1, 1]) +@test r1-n ≈ -(n-r1) ≈ RationalFunction([-4, -2], [1, 1]) +@test r1*n ≈ dot(r1, n) ≈ n*r1 ≈ dot(n, r1) ≈ RationalFunction([-3, 3], [1, 1]) +@test r1/n ≈ inv(n/r1) ≈ RationalFunction([-1, 1], [3, 3]) ≈ RationalFunction([-1, 1]/3, [1, 1]) ## Solution of rational function equalities r1 = RationalFunction([-1, 1], [ 1, 1], :x) # r1 = (x-1)/(x+1) @@ -240,12 +241,12 @@ r3 = RationalFunction([-1, 1], [-1, 1], :s) # r3 = (s-1)/(s-1) @test solve(5, r1) ≈ solve(r1, 5) ≈ [-3/2] @test_throws ErrorException solve(5r3, 5) -### w.r.t `Poly`s -p1 = Poly([-1, 1]) +### w.r.t `Polynomial`s +p1 = Polynomial([-1, 1]) sln1 = solve(r1, p1) sln2 = solve(p1, r1) @test (sln1 ≈ [0, 1] || sln1 ≈ [1, 0]) && (sln2 ≈ [0, 1] || sln2 ≈ [1, 0]) -@test solve(r1, Poly([0])) ≈ [1] +@test solve(r1, Polynomial([0])) ≈ [1] @test_throws DomainError solve(r3, p1) @test_throws ErrorException solve(p1, RationalFunction(p1)) @@ -287,8 +288,12 @@ num2, den2 = residue(r, p, k) num1 = [10, 2] den1 = [0, 10, 2, 1] r, p, k = residue(num1, den1) -@test r ≈ [-0.5-(1/6)im, -0.5+(1/6)im, 1.0+0.0im] -@test p ≈ [-1.0+3.0im, -1.0-3.0im, 0.0+0.0im] +@test length(findall(x -> x ≈ -0.5-(1/6)im, r)) == 1 +@test length(findall(x -> x ≈ -0.5+(1/6)im, r)) == 1 +@test length(findall(x -> x ≈ 1.0+ 0.0im, r)) == 1 +@test length(findall(x -> x ≈ -1.0- 3.0im, p)) == 1 +@test length(findall(x -> x ≈ -1.0+ 3.0im, p)) == 1 +@test length(findall(x -> x ≈ 0.0+ 0.0im, p)) == 1 @test k ≈ [0.0] num2, den2 = residue(r, p, k) #@test num1 ≈ num2 #Cannot pass due to erroneous third, imaginary root. Numerical errors?