313 lines
11 KiB
Julia
313 lines
11 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
import Base: -, *, /, \
|
||
using Base.Test
|
||
|
||
# A custom Quaternion type with minimal defined interface and methods.
|
||
# Used to test scale and scale! methods to show non-commutativity.
|
||
struct Quaternion{T<:Real} <: Number
|
||
s::T
|
||
v1::T
|
||
v2::T
|
||
v3::T
|
||
end
|
||
Quaternion(s::Real, v1::Real, v2::Real, v3::Real) = Quaternion(promote(s, v1, v2, v3)...)
|
||
Base.abs2(q::Quaternion) = q.s*q.s + q.v1*q.v1 + q.v2*q.v2 + q.v3*q.v3
|
||
Base.abs(q::Quaternion) = sqrt(abs2(q))
|
||
Base.real{T}(::Type{Quaternion{T}}) = T
|
||
Base.conj(q::Quaternion) = Quaternion(q.s, -q.v1, -q.v2, -q.v3)
|
||
Base.isfinite(q::Quaternion) = isfinite(q.s) & isfinite(q.v1) & isfinite(q.v2) & isfinite(q.v3)
|
||
|
||
(-)(ql::Quaternion, qr::Quaternion) =
|
||
Quaternion(ql.s - qr.s, ql.v1 - qr.v1, ql.v2 - qr.v2, ql.v3 - qr.v3)
|
||
(*)(q::Quaternion, w::Quaternion) = Quaternion(q.s*w.s - q.v1*w.v1 - q.v2*w.v2 - q.v3*w.v3,
|
||
q.s*w.v1 + q.v1*w.s + q.v2*w.v3 - q.v3*w.v2,
|
||
q.s*w.v2 - q.v1*w.v3 + q.v2*w.s + q.v3*w.v1,
|
||
q.s*w.v3 + q.v1*w.v2 - q.v2*w.v1 + q.v3*w.s)
|
||
(*)(q::Quaternion, r::Real) = Quaternion(q.s*r, q.v1*r, q.v2*r, q.v3*r)
|
||
(*)(q::Quaternion, b::Bool) = b * q # remove method ambiguity
|
||
(/)(q::Quaternion, w::Quaternion) = q * conj(w) * (1.0 / abs2(w))
|
||
(\)(q::Quaternion, w::Quaternion) = conj(q) * w * (1.0 / abs2(q))
|
||
|
||
debug = false
|
||
|
||
srand(123)
|
||
|
||
n = 5 # should be odd
|
||
|
||
for elty in (Int, Rational{BigInt}, Float32, Float64, BigFloat, Complex{Float32}, Complex{Float64}, Complex{BigFloat})
|
||
if elty <: Int
|
||
A = rand(-n:n, n, n) + 10I
|
||
elseif elty <: Rational
|
||
A = Rational{BigInt}[rand(-n:n)/rand(1:n) for i = 1:n, j = 1:n] + 10I
|
||
elseif elty <: Real
|
||
A = convert(Matrix{elty}, randn(n,n)) + 10I
|
||
else
|
||
A = convert(Matrix{elty}, complex.(randn(n,n), randn(n,n)))
|
||
end
|
||
|
||
debug && println("element type: $elty")
|
||
|
||
@test logdet(A) ≈ log(det(A))
|
||
@test logabsdet(A)[1] ≈ log(abs(det(A)))
|
||
@test logabsdet(convert(Matrix{elty}, -eye(n)))[2] == -1
|
||
if elty <: Real
|
||
@test logabsdet(A)[2] == sign(det(A))
|
||
@test_throws DomainError logdet(convert(Matrix{elty}, -eye(n)))
|
||
else
|
||
@test logabsdet(A)[2] ≈ sign(det(A))
|
||
end
|
||
end
|
||
|
||
# test diff, throw ArgumentError for invalid dimension argument
|
||
let X = [3 9 5;
|
||
7 4 2;
|
||
2 1 10]
|
||
@test diff(X,1) == [4 -5 -3; -5 -3 8]
|
||
@test diff(X,2) == [6 -4; -3 -2; -1 9]
|
||
@test diff(view(X, 1:2, 1:2),1) == [4 -5]
|
||
@test diff(view(X, 1:2, 1:2),2) == reshape([6; -3], (2,1))
|
||
@test diff(view(X, 2:3, 2:3),1) == [-3 8]
|
||
@test diff(view(X, 2:3, 2:3),2) == reshape([-2; 9], (2,1))
|
||
@test_throws ArgumentError diff(X,3)
|
||
@test_throws ArgumentError diff(X,-1)
|
||
end
|
||
|
||
# test linrange
|
||
# make sure unequal input arrays throw an error
|
||
x = [2; 5; 6]
|
||
y = [3; 7; 10; 10]
|
||
@test_throws DimensionMismatch linreg(x, y)
|
||
x = [2 5 6]
|
||
y = [3; 7; 10]
|
||
@test_throws MethodError linreg(x, y)
|
||
|
||
# check (UnitRange, Array)
|
||
x = 1:12
|
||
y = [5.5; 6.3; 7.6; 8.8; 10.9; 11.79; 13.48; 15.02; 17.77; 20.81; 22.0; 22.99]
|
||
@test [linreg(x,y)...] ≈ [2.5559090909090867, 1.6960139860139862]
|
||
@test [linreg(view(x,1:6),view(y,1:6))...] ≈ [3.8366666666666642,1.3271428571428574]
|
||
|
||
# check (LinSpace, UnitRange)
|
||
x = linspace(1.0, 12.0, 100)
|
||
y = -100:-1
|
||
@test [linreg(x, y)...] ≈ [-109.0, 9.0]
|
||
|
||
# check (UnitRange, UnitRange)
|
||
x = 1:12
|
||
y = 12:-1:1
|
||
@test [linreg(x, y)...] ≈ [13.0, -1.0]
|
||
|
||
# check (LinSpace, LinSpace)
|
||
x = linspace(-5, 10, 100)
|
||
y = linspace(50, 200, 100)
|
||
@test [linreg(x, y)...] ≈ [100.0, 10.0]
|
||
|
||
# check (Array, Array)
|
||
# Anscombe's quartet (https://en.wikipedia.org/wiki/Anscombe%27s_quartet)
|
||
x123 = [10.0; 8.0; 13.0; 9.0; 11.0; 14.0; 6.0; 4.0; 12.0; 7.0; 5.0]
|
||
y1 = [8.04; 6.95; 7.58; 8.81; 8.33; 9.96; 7.24; 4.26; 10.84; 4.82; 5.68]
|
||
@test [linreg(x123,y1)...] ≈ [3.0,0.5] atol=15e-5
|
||
|
||
y2 = [9.14; 8.14; 8.74; 8.77; 9.26; 8.10; 6.12; 3.10; 9.13; 7.26; 4.74]
|
||
@test [linreg(x123,y2)...] ≈ [3.0,0.5] atol=10e-3
|
||
|
||
y3 = [7.46; 6.77; 12.74; 7.11; 7.81; 8.84; 6.08; 5.39; 8.15; 6.42; 5.73]
|
||
@test [linreg(x123,y3)...] ≈ [3.0,0.5] atol=10e-3
|
||
|
||
x4 = [8.0; 8.0; 8.0; 8.0; 8.0; 8.0; 8.0; 19.0; 8.0; 8.0; 8.0]
|
||
y4 = [6.58; 5.76; 7.71; 8.84; 8.47; 7.04; 5.25; 12.50; 5.56; 7.91; 6.89]
|
||
@test [linreg(x4,y4)...] ≈ [3.0,0.5] atol=10e-3
|
||
|
||
# test diag
|
||
let A = eye(4)
|
||
@test diag(A) == ones(4)
|
||
@test diag(view(A, 1:3, 1:3)) == ones(3)
|
||
@test diag(view(A, 1:2, 1:2)) == ones(2)
|
||
end
|
||
|
||
# test generic axpy
|
||
x = ['a','b','c','d','e']
|
||
y = ['a','b','c','d','e']
|
||
α = 'f'
|
||
@test_throws DimensionMismatch Base.LinAlg.axpy!(α,x,['g'])
|
||
@test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(-1:5),y,collect(1:7))
|
||
@test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(1:7),y,collect(-1:5))
|
||
@test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(1:7),y,collect(1:7))
|
||
@test_throws DimensionMismatch Base.LinAlg.axpy!(α,x,collect(1:3),y,collect(1:5))
|
||
|
||
@test_throws ArgumentError diag(rand(10))
|
||
@test !issymmetric(ones(5,3))
|
||
@test !ishermitian(ones(5,3))
|
||
@test cross(ones(3),ones(3)) == zeros(3)
|
||
|
||
@test trace(Bidiagonal(ones(5),zeros(4),true)) == 5
|
||
|
||
|
||
# array and subarray tests
|
||
let aa = reshape([1.:6;], (2,3))
|
||
for atype in ("Array", "SubArray")
|
||
if atype == "Array"
|
||
a = aa
|
||
else
|
||
a = view(aa, 1:2, 1:2)
|
||
end
|
||
|
||
# 2-argument version of scale!
|
||
@test scale!(copy(a), 5.) == a*5
|
||
@test scale!(5., copy(a)) == a*5
|
||
b = randn(Base.LinAlg.SCAL_CUTOFF) # make sure we try BLAS path
|
||
subB = view(b, :, :)
|
||
@test scale!(copy(b), 5.) == b*5
|
||
@test scale!(copy(subB), 5.) == subB*5
|
||
@test scale!([1.; 2.], copy(a)) == a.*[1; 2]
|
||
@test scale!([1; 2], copy(a)) == a.*[1; 2]
|
||
@test_throws DimensionMismatch scale!(ones(3), a)
|
||
|
||
if atype == "Array"
|
||
@test scale!(copy(a), [1.; 2.; 3.]) == a.*[1 2 3]
|
||
@test scale!(copy(a), [1; 2; 3]) == a.*[1 2 3]
|
||
@test_throws DimensionMismatch scale!(a, ones(2))
|
||
else
|
||
@test scale!(copy(a), [1.; 2.]) == a.*[1 2]
|
||
@test scale!(copy(a), [1; 2]) == a.*[1 2]
|
||
@test_throws DimensionMismatch scale!(a, ones(3))
|
||
end
|
||
|
||
# 3-argument version of scale!
|
||
@test scale!(similar(a), 5., a) == a*5
|
||
@test scale!(similar(a), a, 5.) == a*5
|
||
@test scale!(similar(a), [1.; 2.], a) == a.*[1; 2]
|
||
@test scale!(similar(a), [1; 2], a) == a.*[1; 2]
|
||
@test_throws DimensionMismatch scale!(similar(a), ones(3), a)
|
||
@test_throws DimensionMismatch scale!(Array{Float64}(3, 2), a, ones(3))
|
||
|
||
if atype == "Array"
|
||
@test scale!(similar(a), a, [1.; 2.; 3.]) == a.*[1 2 3]
|
||
@test scale!(similar(a), a, [1; 2; 3]) == a.*[1 2 3]
|
||
@test_throws DimensionMismatch scale!(similar(a), a, ones(2))
|
||
else
|
||
@test scale!(similar(a), a, [1.; 2.]) == a.*[1 2]
|
||
@test scale!(similar(a), a, [1; 2]) == a.*[1 2]
|
||
@test_throws DimensionMismatch scale!(similar(a), a, ones(3))
|
||
end
|
||
end
|
||
end
|
||
|
||
# scale real matrix by complex type
|
||
@test_throws InexactError scale!([1.0], 2.0im)
|
||
@test isequal([1.0] * 2.0im, Complex{Float64}[2.0im])
|
||
@test isequal(2.0im * [1.0], Complex{Float64}[2.0im])
|
||
@test isequal(Float32[1.0] * 2.0f0im, Complex{Float32}[2.0im])
|
||
@test isequal(Float32[1.0] * 2.0im, Complex{Float64}[2.0im])
|
||
@test isequal(Float64[1.0] * 2.0f0im, Complex{Float64}[2.0im])
|
||
@test isequal(Float32[1.0] * big(2.0)im, Complex{BigFloat}[2.0im])
|
||
@test isequal(Float64[1.0] * big(2.0)im, Complex{BigFloat}[2.0im])
|
||
@test isequal(BigFloat[1.0] * 2.0im, Complex{BigFloat}[2.0im])
|
||
@test isequal(BigFloat[1.0] * 2.0f0im, Complex{BigFloat}[2.0im])
|
||
|
||
# test scale and scale! for non-commutative multiplication
|
||
q = Quaternion(0.44567, 0.755871, 0.882548, 0.423612)
|
||
qmat = [Quaternion(0.015007, 0.355067, 0.418645, 0.318373)]
|
||
@test scale!(q, copy(qmat)) != scale!(copy(qmat), q)
|
||
## Test * because it doesn't dispatch to scale!
|
||
@test q*qmat ≉ qmat*q
|
||
@test conj(q*qmat) ≈ conj(qmat)*conj(q)
|
||
@test q * (q \ qmat) ≈ qmat ≈ (qmat / q) * q
|
||
@test q\qmat ≉ qmat/q
|
||
|
||
# test ops on Numbers
|
||
for elty in [Float32,Float64,Complex64,Complex128]
|
||
a = rand(elty)
|
||
@test trace(a) == a
|
||
@test rank(zero(elty)) == 0
|
||
@test rank(one(elty)) == 1
|
||
@test !isfinite(cond(zero(elty)))
|
||
@test cond(a) == one(elty)
|
||
@test cond(a,1) == one(elty)
|
||
@test issymmetric(a)
|
||
@test ishermitian(one(elty))
|
||
@test det(a) == a
|
||
end
|
||
|
||
@test !issymmetric(NaN16)
|
||
@test !issymmetric(NaN32)
|
||
@test !issymmetric(NaN)
|
||
|
||
@test rank([1.0 0.0; 0.0 0.9],0.95) == 1
|
||
@test qr(big.([0 1; 0 0]))[2] == [0 1; 0 0]
|
||
|
||
@test norm([2.4e-322, 4.4e-323]) ≈ 2.47e-322
|
||
@test norm([2.4e-322, 4.4e-323], 3) ≈ 2.4e-322
|
||
@test_throws ArgumentError norm(ones(5,5),5)
|
||
|
||
# test generic vecnorm for arrays of arrays
|
||
let x = Vector{Int}[[1,2], [3,4]]
|
||
@test norm(x) ≈ sqrt(30)
|
||
@test norm(x, 1) ≈ sqrt(5) + 5
|
||
@test norm(x, 3) ≈ cbrt(sqrt(125)+125)
|
||
end
|
||
|
||
# test that LinAlg.axpy! works for element type without commutative multiplication
|
||
let
|
||
α = ones(Int, 2, 2)
|
||
x = fill([1 0; 1 1], 3)
|
||
y = fill(zeros(Int, 2, 2), 3)
|
||
@test LinAlg.axpy!(α, x, deepcopy(y)) == x .* Matrix{Int}[α]
|
||
@test LinAlg.axpy!(α, x, deepcopy(y)) != Matrix{Int}[α] .* x
|
||
end
|
||
|
||
# test that LinAlg.axpy! works for x and y of different dimensions
|
||
let
|
||
α = 5
|
||
x = 2:5
|
||
y = ones(Int, 2, 4)
|
||
rx = [1 4]
|
||
ry = [2 8]
|
||
@test LinAlg.axpy!(α, x, rx, y, ry) == [1 1 1 1; 11 1 1 26]
|
||
end
|
||
|
||
let
|
||
vr = [3.0, 4.0]
|
||
for Tr in (Float32, Float64)
|
||
for T in (Tr, Complex{Tr})
|
||
v = convert(Vector{T}, vr)
|
||
@test norm(v) == 5.0
|
||
w = normalize(v)
|
||
@test norm(w - [0.6, 0.8], Inf) < eps(Tr)
|
||
@test norm(w) == 1.0
|
||
@test norm(normalize!(copy(v)) - w, Inf) < eps(Tr)
|
||
@test isempty(normalize!(T[]))
|
||
end
|
||
end
|
||
end
|
||
|
||
#Test potential overflow in normalize!
|
||
let
|
||
δ = inv(prevfloat(typemax(Float64)))
|
||
v = [δ, -δ]
|
||
|
||
@test norm(v) === 7.866824069956793e-309
|
||
w = normalize(v)
|
||
@test w ≈ [1/√2, -1/√2]
|
||
@test norm(w) === 1.0
|
||
@test norm(normalize!(v) - w, Inf) < eps()
|
||
end
|
||
|
||
# Issue 14657
|
||
@test det([true false; false true]) == det(eye(Int, 2))
|
||
|
||
@test_throws ArgumentError Base.LinAlg.char_uplo(:Z)
|
||
|
||
# Issue 17650
|
||
@test [0.01311489462160816, Inf] ≈ [0.013114894621608135, Inf]
|
||
|
||
# Issue 19035
|
||
@test Base.LinAlg.promote_leaf_eltypes([1, 2, [3.0, 4.0]]) == Float64
|
||
@test Base.LinAlg.promote_leaf_eltypes([[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]]) == Complex128
|
||
@test [1, 2, 3] ≈ [1, 2, 3]
|
||
@test [[1, 2], [3, 4]] ≈ [[1, 2], [3, 4]]
|
||
@test [[1, 2], [3, 4]] ≈ [[1.0-eps(), 2.0+eps()], [3.0+2eps(), 4.0-1e8eps()]]
|
||
@test [[1, 2], [3, 4]] ≉ [[1.0-eps(), 2.0+eps()], [3.0+2eps(), 4.0-1e9eps()]]
|
||
@test [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]] ≈ [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]]
|