976 lines
20 KiB
Julia
976 lines
20 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
## types ##
|
||
|
||
"""
|
||
<:(T1, T2)
|
||
|
||
Subtype operator, equivalent to `issubtype(T1, T2)`.
|
||
|
||
```jldoctest
|
||
julia> Float64 <: AbstractFloat
|
||
true
|
||
|
||
julia> Vector{Int} <: AbstractArray
|
||
true
|
||
|
||
julia> Matrix{Float64} <: Matrix{AbstractFloat}
|
||
false
|
||
```
|
||
"""
|
||
const (<:) = issubtype
|
||
|
||
"""
|
||
>:(T1, T2)
|
||
|
||
Supertype operator, equivalent to `issubtype(T2, T1)`.
|
||
"""
|
||
const (>:)(a::ANY, b::ANY) = issubtype(b, a)
|
||
|
||
"""
|
||
supertype(T::DataType)
|
||
|
||
Return the supertype of DataType `T`.
|
||
|
||
```jldoctest
|
||
julia> supertype(Int32)
|
||
Signed
|
||
```
|
||
"""
|
||
function supertype(T::DataType)
|
||
@_pure_meta
|
||
T.super
|
||
end
|
||
|
||
function supertype(T::UnionAll)
|
||
@_pure_meta
|
||
UnionAll(T.var, supertype(T.body))
|
||
end
|
||
|
||
## generic comparison ##
|
||
|
||
==(x, y) = x === y
|
||
|
||
"""
|
||
isequal(x, y)
|
||
|
||
Similar to `==`, except treats all floating-point `NaN` values as equal to each other, and
|
||
treats `-0.0` as unequal to `0.0`. The default implementation of `isequal` calls `==`, so if
|
||
you have a type that doesn't have these floating-point subtleties then you probably only
|
||
need to define `==`.
|
||
|
||
`isequal` is the comparison function used by hash tables (`Dict`). `isequal(x,y)` must imply
|
||
that `hash(x) == hash(y)`.
|
||
|
||
This typically means that if you define your own `==` function then you must define a
|
||
corresponding `hash` (and vice versa). Collections typically implement `isequal` by calling
|
||
`isequal` recursively on all contents.
|
||
|
||
Scalar types generally do not need to implement `isequal` separate from `==`, unless they
|
||
represent floating-point numbers amenable to a more efficient implementation than that
|
||
provided as a generic fallback (based on `isnan`, `signbit`, and `==`).
|
||
|
||
```jldoctest
|
||
julia> isequal([1., NaN], [1., NaN])
|
||
true
|
||
|
||
julia> [1., NaN] == [1., NaN]
|
||
false
|
||
|
||
julia> 0.0 == -0.0
|
||
true
|
||
|
||
julia> isequal(0.0, -0.0)
|
||
false
|
||
```
|
||
"""
|
||
isequal(x, y) = x == y
|
||
|
||
signequal(x, y) = signbit(x)::Bool == signbit(y)::Bool
|
||
signless(x, y) = signbit(x)::Bool & !signbit(y)::Bool
|
||
|
||
isequal(x::AbstractFloat, y::AbstractFloat) = (isnan(x) & isnan(y)) | signequal(x, y) & (x == y)
|
||
isequal(x::Real, y::AbstractFloat) = (isnan(x) & isnan(y)) | signequal(x, y) & (x == y)
|
||
isequal(x::AbstractFloat, y::Real ) = (isnan(x) & isnan(y)) | signequal(x, y) & (x == y)
|
||
|
||
isless(x::AbstractFloat, y::AbstractFloat) = (!isnan(x) & isnan(y)) | signless(x, y) | (x < y)
|
||
isless(x::Real, y::AbstractFloat) = (!isnan(x) & isnan(y)) | signless(x, y) | (x < y)
|
||
isless(x::AbstractFloat, y::Real ) = (!isnan(x) & isnan(y)) | signless(x, y) | (x < y)
|
||
|
||
|
||
function ==(T::Type, S::Type)
|
||
@_pure_meta
|
||
typeseq(T, S)
|
||
end
|
||
function !=(T::Type, S::Type)
|
||
@_pure_meta
|
||
!(T == S)
|
||
end
|
||
==(T::TypeVar, S::Type) = false
|
||
==(T::Type, S::TypeVar) = false
|
||
|
||
## comparison fallbacks ##
|
||
|
||
"""
|
||
!=(x, y)
|
||
≠(x,y)
|
||
|
||
Not-equals comparison operator. Always gives the opposite answer as `==`. New types should
|
||
generally not implement this, and rely on the fallback definition `!=(x,y) = !(x==y)` instead.
|
||
|
||
```jldoctest
|
||
julia> 3 != 2
|
||
true
|
||
|
||
julia> "foo" ≠ "foo"
|
||
false
|
||
```
|
||
"""
|
||
!=(x, y) = !(x == y)::Bool
|
||
const ≠ = !=
|
||
|
||
"""
|
||
===(x,y) -> Bool
|
||
≡(x,y) -> Bool
|
||
|
||
Determine whether `x` and `y` are identical, in the sense that no program could distinguish
|
||
them. Compares mutable objects by address in memory, and compares immutable objects (such as
|
||
numbers) by contents at the bit level. This function is sometimes called `egal`.
|
||
|
||
```jldoctest
|
||
julia> a = [1, 2]; b = [1, 2];
|
||
|
||
julia> a == b
|
||
true
|
||
|
||
julia> a === b
|
||
false
|
||
|
||
julia> a === a
|
||
true
|
||
```
|
||
"""
|
||
===
|
||
const ≡ = ===
|
||
|
||
"""
|
||
!==(x, y)
|
||
≢(x,y)
|
||
|
||
Equivalent to `!(x === y)`.
|
||
|
||
```jldoctest
|
||
julia> a = [1, 2]; b = [1, 2];
|
||
|
||
julia> a ≢ b
|
||
true
|
||
|
||
julia> a ≢ a
|
||
false
|
||
```
|
||
"""
|
||
!==(x, y) = !(x === y)
|
||
const ≢ = !==
|
||
|
||
"""
|
||
<(x, y)
|
||
|
||
Less-than comparison operator. New numeric types should implement this function for two
|
||
arguments of the new type. Because of the behavior of floating-point NaN values, `<`
|
||
implements a partial order. Types with a canonical partial order should implement `<`, and
|
||
types with a canonical total order should implement `isless`.
|
||
|
||
```jldoctest
|
||
julia> 'a' < 'b'
|
||
true
|
||
|
||
julia> "abc" < "abd"
|
||
true
|
||
|
||
julia> 5 < 3
|
||
false
|
||
```
|
||
"""
|
||
<(x, y) = isless(x, y)
|
||
|
||
"""
|
||
>(x, y)
|
||
|
||
Greater-than comparison operator. Generally, new types should implement `<` instead of this
|
||
function, and rely on the fallback definition `>(x, y) = y < x`.
|
||
|
||
```jldoctest
|
||
julia> 'a' > 'b'
|
||
false
|
||
|
||
julia> 7 > 3 > 1
|
||
true
|
||
|
||
julia> "abc" > "abd"
|
||
false
|
||
|
||
julia> 5 > 3
|
||
true
|
||
```
|
||
"""
|
||
>(x, y) = y < x
|
||
|
||
"""
|
||
<=(x, y)
|
||
≤(x,y)
|
||
|
||
Less-than-or-equals comparison operator.
|
||
|
||
```jldoctest
|
||
julia> 'a' <= 'b'
|
||
true
|
||
|
||
julia> 7 ≤ 7 ≤ 9
|
||
true
|
||
|
||
julia> "abc" ≤ "abc"
|
||
true
|
||
|
||
julia> 5 <= 3
|
||
false
|
||
```
|
||
"""
|
||
<=(x, y) = !(y < x)
|
||
const ≤ = <=
|
||
|
||
"""
|
||
>=(x, y)
|
||
≥(x,y)
|
||
|
||
Greater-than-or-equals comparison operator.
|
||
|
||
```jldoctest
|
||
julia> 'a' >= 'b'
|
||
false
|
||
|
||
julia> 7 ≥ 7 ≥ 3
|
||
true
|
||
|
||
julia> "abc" ≥ "abc"
|
||
true
|
||
|
||
julia> 5 >= 3
|
||
true
|
||
```
|
||
"""
|
||
>=(x, y) = (y <= x)
|
||
const ≥ = >=
|
||
|
||
# this definition allows Number types to implement < instead of isless,
|
||
# which is more idiomatic:
|
||
isless(x::Real, y::Real) = x<y
|
||
lexcmp(x::Real, y::Real) = isless(x,y) ? -1 : ifelse(isless(y,x), 1, 0)
|
||
|
||
"""
|
||
ifelse(condition::Bool, x, y)
|
||
|
||
Return `x` if `condition` is `true`, otherwise return `y`. This differs from `?` or `if` in
|
||
that it is an ordinary function, so all the arguments are evaluated first. In some cases,
|
||
using `ifelse` instead of an `if` statement can eliminate the branch in generated code and
|
||
provide higher performance in tight loops.
|
||
|
||
```jldoctest
|
||
julia> ifelse(1 > 2, 1, 2)
|
||
2
|
||
```
|
||
"""
|
||
ifelse(c::Bool, x, y) = select_value(c, x, y)
|
||
|
||
"""
|
||
cmp(x,y)
|
||
|
||
Return -1, 0, or 1 depending on whether `x` is less than, equal to, or greater than `y`,
|
||
respectively. Uses the total order implemented by `isless`. For floating-point numbers, uses `<`
|
||
but throws an error for unordered arguments.
|
||
|
||
```jldoctest
|
||
julia> cmp(1, 2)
|
||
-1
|
||
|
||
julia> cmp(2, 1)
|
||
1
|
||
|
||
julia> cmp(2+im, 3-im)
|
||
ERROR: MethodError: no method matching isless(::Complex{Int64}, ::Complex{Int64})
|
||
[...]
|
||
```
|
||
"""
|
||
cmp(x, y) = isless(x, y) ? -1 : ifelse(isless(y, x), 1, 0)
|
||
|
||
"""
|
||
lexcmp(x, y)
|
||
|
||
Compare `x` and `y` lexicographically and return -1, 0, or 1 depending on whether `x` is
|
||
less than, equal to, or greater than `y`, respectively. This function should be defined for
|
||
lexicographically comparable types, and `lexless` will call `lexcmp` by default.
|
||
|
||
```jldoctest
|
||
julia> lexcmp("abc", "abd")
|
||
-1
|
||
|
||
julia> lexcmp("abc", "abc")
|
||
0
|
||
```
|
||
"""
|
||
lexcmp(x, y) = cmp(x, y)
|
||
|
||
"""
|
||
lexless(x, y)
|
||
|
||
Determine whether `x` is lexicographically less than `y`.
|
||
|
||
```jldoctest
|
||
julia> lexless("abc", "abd")
|
||
true
|
||
```
|
||
"""
|
||
lexless(x, y) = lexcmp(x,y) < 0
|
||
|
||
# cmp returns -1, 0, +1 indicating ordering
|
||
cmp(x::Integer, y::Integer) = ifelse(isless(x, y), -1, ifelse(isless(y, x), 1, 0))
|
||
|
||
"""
|
||
max(x, y, ...)
|
||
|
||
Return the maximum of the arguments. See also the [`maximum`](@ref) function
|
||
to take the maximum element from a collection.
|
||
|
||
```jldoctest
|
||
julia> max(2, 5, 1)
|
||
5
|
||
```
|
||
"""
|
||
max(x, y) = ifelse(y < x, x, y)
|
||
|
||
"""
|
||
min(x, y, ...)
|
||
|
||
Return the minimum of the arguments. See also the [`minimum`](@ref) function
|
||
to take the minimum element from a collection.
|
||
|
||
```jldoctest
|
||
julia> min(2, 5, 1)
|
||
1
|
||
```
|
||
"""
|
||
min(x,y) = ifelse(y < x, y, x)
|
||
|
||
"""
|
||
minmax(x, y)
|
||
|
||
Return `(min(x,y), max(x,y))`. See also: [`extrema`](@ref) that returns `(minimum(x), maximum(x))`.
|
||
|
||
```jldoctest
|
||
julia> minmax('c','b')
|
||
('b', 'c')
|
||
```
|
||
"""
|
||
minmax(x,y) = y < x ? (y, x) : (x, y)
|
||
|
||
scalarmax(x,y) = max(x,y)
|
||
scalarmax(x::AbstractArray, y::AbstractArray) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
scalarmax(x , y::AbstractArray) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
scalarmax(x::AbstractArray, y ) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
|
||
scalarmin(x,y) = min(x,y)
|
||
scalarmin(x::AbstractArray, y::AbstractArray) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
scalarmin(x , y::AbstractArray) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
scalarmin(x::AbstractArray, y ) = throw(ArgumentError("ordering is not well-defined for arrays"))
|
||
|
||
## definitions providing basic traits of arithmetic operators ##
|
||
|
||
"""
|
||
identity(x)
|
||
|
||
The identity function. Returns its argument.
|
||
|
||
```jldoctest
|
||
julia> identity("Well, what did you expect?")
|
||
"Well, what did you expect?"
|
||
```
|
||
"""
|
||
identity(x) = x
|
||
|
||
+(x::Number) = x
|
||
*(x::Number) = x
|
||
(&)(x::Integer) = x
|
||
(|)(x::Integer) = x
|
||
xor(x::Integer) = x
|
||
|
||
const ⊻ = xor
|
||
|
||
# foldl for argument lists. expand recursively up to a point, then
|
||
# switch to a loop. this allows small cases like `a+b+c+d` to be inlined
|
||
# efficiently, without a major slowdown for `+(x...)` when `x` is big.
|
||
afoldl(op,a) = a
|
||
afoldl(op,a,b) = op(a,b)
|
||
afoldl(op,a,b,c...) = afoldl(op, op(a,b), c...)
|
||
function afoldl(op,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,qs...)
|
||
y = op(op(op(op(op(op(op(op(op(op(op(op(op(op(op(a,b),c),d),e),f),g),h),i),j),k),l),m),n),o),p)
|
||
for x in qs; y = op(y,x); end
|
||
y
|
||
end
|
||
|
||
for op in (:+, :*, :&, :|, :xor, :min, :max, :kron)
|
||
@eval begin
|
||
# note: these definitions must not cause a dispatch loop when +(a,b) is
|
||
# not defined, and must only try to call 2-argument definitions, so
|
||
# that defining +(a,b) is sufficient for full functionality.
|
||
($op)(a, b, c, xs...) = afoldl($op, ($op)(($op)(a,b),c), xs...)
|
||
# a further concern is that it's easy for a type like (Int,Int...)
|
||
# to match many definitions, so we need to keep the number of
|
||
# definitions down to avoid losing type information.
|
||
end
|
||
end
|
||
|
||
"""
|
||
\\(x, y)
|
||
|
||
Left division operator: multiplication of `y` by the inverse of `x` on the left. Gives
|
||
floating-point results for integer arguments.
|
||
|
||
```jldoctest
|
||
julia> 3 \\ 6
|
||
2.0
|
||
|
||
julia> inv(3) * 6
|
||
2.0
|
||
|
||
julia> A = [1 2; 3 4]; x = [5, 6];
|
||
|
||
julia> A \\ x
|
||
2-element Array{Float64,1}:
|
||
-4.0
|
||
4.5
|
||
|
||
julia> inv(A) * x
|
||
2-element Array{Float64,1}:
|
||
-4.0
|
||
4.5
|
||
```
|
||
"""
|
||
\(x,y) = (y'/x')'
|
||
|
||
# Core <<, >>, and >>> take either Int or UInt as second arg. Signed shift
|
||
# counts can shift in either direction, and are translated here to unsigned
|
||
# counts. Integer datatypes only need to implement the unsigned version.
|
||
|
||
"""
|
||
<<(x, n)
|
||
|
||
Left bit shift operator, `x << n`. For `n >= 0`, the result is `x` shifted left
|
||
by `n` bits, filling with `0`s. This is equivalent to `x * 2^n`. For `n < 0`,
|
||
this is equivalent to `x >> -n`.
|
||
|
||
```jldoctest
|
||
julia> Int8(3) << 2
|
||
12
|
||
|
||
julia> bits(Int8(3))
|
||
"00000011"
|
||
|
||
julia> bits(Int8(12))
|
||
"00001100"
|
||
```
|
||
See also [`>>`](@ref), [`>>>`](@ref).
|
||
"""
|
||
function <<(x::Integer, c::Integer)
|
||
@_inline_meta
|
||
typemin(Int) <= c <= typemax(Int) && return x << (c % Int)
|
||
(x >= 0 || c >= 0) && return zero(x)
|
||
oftype(x, -1)
|
||
end
|
||
<<(x::Integer, c::Unsigned) = c <= typemax(UInt) ? x << (c % UInt) : zero(x)
|
||
<<(x::Integer, c::Int) = c >= 0 ? x << unsigned(c) : x >> unsigned(-c)
|
||
|
||
"""
|
||
>>(x, n)
|
||
|
||
Right bit shift operator, `x >> n`. For `n >= 0`, the result is `x` shifted
|
||
right by `n` bits, where `n >= 0`, filling with `0`s if `x >= 0`, `1`s if `x <
|
||
0`, preserving the sign of `x`. This is equivalent to `fld(x, 2^n)`. For `n <
|
||
0`, this is equivalent to `x << -n`.
|
||
|
||
|
||
```jldoctest
|
||
julia> Int8(13) >> 2
|
||
3
|
||
|
||
julia> bits(Int8(13))
|
||
"00001101"
|
||
|
||
julia> bits(Int8(3))
|
||
"00000011"
|
||
|
||
julia> Int8(-14) >> 2
|
||
-4
|
||
|
||
julia> bits(Int8(-14))
|
||
"11110010"
|
||
|
||
julia> bits(Int8(-4))
|
||
"11111100"
|
||
```
|
||
See also [`>>>`](@ref), [`<<`](@ref).
|
||
"""
|
||
function >>(x::Integer, c::Integer)
|
||
@_inline_meta
|
||
typemin(Int) <= c <= typemax(Int) && return x >> (c % Int)
|
||
(x >= 0 || c < 0) && return zero(x)
|
||
oftype(x, -1)
|
||
end
|
||
>>(x::Integer, c::Unsigned) = c <= typemax(UInt) ? x >> (c % UInt) : zero(x)
|
||
>>(x::Integer, c::Int) = c >= 0 ? x >> unsigned(c) : x << unsigned(-c)
|
||
|
||
"""
|
||
>>>(x, n)
|
||
|
||
Unsigned right bit shift operator, `x >>> n`. For `n >= 0`, the result is `x`
|
||
shifted right by `n` bits, where `n >= 0`, filling with `0`s. For `n < 0`, this
|
||
is equivalent to `x << -n`.
|
||
|
||
For [`Unsigned`](@ref) integer types, this is equivalent to [`>>`](@ref). For
|
||
[`Signed`](@ref) integer types, this is equivalent to `signed(unsigned(x) >> n)`.
|
||
|
||
```jldoctest
|
||
julia> Int8(-14) >>> 2
|
||
60
|
||
|
||
julia> bits(Int8(-14))
|
||
"11110010"
|
||
|
||
julia> bits(Int8(60))
|
||
"00111100"
|
||
```
|
||
|
||
[`BigInt`](@ref)s are treated as if having infinite size, so no filling is required and this
|
||
is equivalent to [`>>`](@ref).
|
||
|
||
See also [`>>`](@ref), [`<<`](@ref).
|
||
"""
|
||
function >>>(x::Integer, c::Integer)
|
||
@_inline_meta
|
||
typemin(Int) <= c <= typemax(Int) ? x >>> (c % Int) : zero(x)
|
||
end
|
||
>>>(x::Integer, c::Unsigned) = c <= typemax(UInt) ? x >>> (c % UInt) : zero(x)
|
||
>>>(x::Integer, c::Int) = c >= 0 ? x >>> unsigned(c) : x << unsigned(-c)
|
||
|
||
# fallback div, fld, and cld implementations
|
||
# NOTE: C89 fmod() and x87 FPREM implicitly provide truncating float division,
|
||
# so it is used here as the basis of float div().
|
||
div{T<:Real}(x::T, y::T) = convert(T,round((x-rem(x,y))/y))
|
||
|
||
"""
|
||
fld(x, y)
|
||
|
||
Largest integer less than or equal to `x/y`.
|
||
|
||
```jldoctest
|
||
julia> fld(7.3,5.5)
|
||
1.0
|
||
```
|
||
"""
|
||
fld{T<:Real}(x::T, y::T) = convert(T,round((x-mod(x,y))/y))
|
||
|
||
"""
|
||
cld(x, y)
|
||
|
||
Smallest integer larger than or equal to `x/y`.
|
||
```jldoctest
|
||
julia> cld(5.5,2.2)
|
||
3.0
|
||
```
|
||
"""
|
||
cld{T<:Real}(x::T, y::T) = convert(T,round((x-modCeil(x,y))/y))
|
||
#rem{T<:Real}(x::T, y::T) = convert(T,x-y*trunc(x/y))
|
||
#mod{T<:Real}(x::T, y::T) = convert(T,x-y*floor(x/y))
|
||
modCeil{T<:Real}(x::T, y::T) = convert(T,x-y*ceil(x/y))
|
||
|
||
# operator alias
|
||
|
||
"""
|
||
rem(x, y)
|
||
%(x, y)
|
||
|
||
Remainder from Euclidean division, returning a value of the same sign as `x`, and smaller in
|
||
magnitude than `y`. This value is always exact.
|
||
|
||
```jldoctest
|
||
julia> x = 15; y = 4;
|
||
|
||
julia> x % y
|
||
3
|
||
|
||
julia> x == div(x, y) * y + rem(x, y)
|
||
true
|
||
```
|
||
"""
|
||
rem
|
||
const % = rem
|
||
|
||
"""
|
||
div(x, y)
|
||
÷(x, y)
|
||
|
||
The quotient from Euclidean division. Computes `x/y`, truncated to an integer.
|
||
|
||
```jldoctest
|
||
julia> 9 ÷ 4
|
||
2
|
||
|
||
julia> -5 ÷ 3
|
||
-1
|
||
```
|
||
"""
|
||
div
|
||
const ÷ = div
|
||
|
||
"""
|
||
mod1(x, y)
|
||
|
||
Modulus after flooring division, returning a value `r` such that `mod(r, y) == mod(x, y)`
|
||
in the range ``(0, y]`` for positive `y` and in the range ``[y,0)`` for negative `y`.
|
||
|
||
```jldoctest
|
||
julia> mod1(4, 2)
|
||
2
|
||
|
||
julia> mod1(4, 3)
|
||
1
|
||
```
|
||
"""
|
||
mod1{T<:Real}(x::T, y::T) = (m = mod(x, y); ifelse(m == 0, y, m))
|
||
# efficient version for integers
|
||
mod1{T<:Integer}(x::T, y::T) = (@_inline_meta; mod(x + y - T(1), y) + T(1))
|
||
|
||
|
||
"""
|
||
fld1(x, y)
|
||
|
||
Flooring division, returning a value consistent with `mod1(x,y)`
|
||
|
||
See also: [`mod1`](@ref).
|
||
|
||
```jldoctest
|
||
julia> x = 15; y = 4;
|
||
|
||
julia> fld1(x, y)
|
||
4
|
||
|
||
julia> x == fld(x, y) * y + mod(x, y)
|
||
true
|
||
|
||
julia> x == (fld1(x, y) - 1) * y + mod1(x, y)
|
||
true
|
||
```
|
||
"""
|
||
fld1(x::T, y::T) where {T<:Real} = (m=mod(x,y); fld(x-m,y))
|
||
# efficient version for integers
|
||
fld1(x::T, y::T) where {T<:Integer} = fld(x+y-T(1),y)
|
||
|
||
"""
|
||
fldmod1(x, y)
|
||
|
||
Return `(fld1(x,y), mod1(x,y))`.
|
||
|
||
See also: [`fld1`](@ref), [`mod1`](@ref).
|
||
"""
|
||
fldmod1(x::T, y::T) where {T<:Real} = (fld1(x,y), mod1(x,y))
|
||
# efficient version for integers
|
||
fldmod1(x::T, y::T) where {T<:Integer} = (fld1(x,y), mod1(x,y))
|
||
|
||
# transpose
|
||
|
||
"""
|
||
ctranspose(A)
|
||
|
||
The conjugate transposition operator (`'`).
|
||
|
||
# Example
|
||
|
||
```jldoctest
|
||
julia> A = [3+2im 9+2im; 8+7im 4+6im]
|
||
2×2 Array{Complex{Int64},2}:
|
||
3+2im 9+2im
|
||
8+7im 4+6im
|
||
|
||
julia> ctranspose(A)
|
||
2×2 Array{Complex{Int64},2}:
|
||
3-2im 8-7im
|
||
9-2im 4-6im
|
||
```
|
||
"""
|
||
ctranspose(x) = conj(transpose(x))
|
||
conj(x) = x
|
||
|
||
# transposed multiply
|
||
|
||
"""
|
||
Ac_mul_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ⋅B``.
|
||
"""
|
||
Ac_mul_B(a,b) = ctranspose(a)*b
|
||
|
||
"""
|
||
A_mul_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᴴ``.
|
||
"""
|
||
A_mul_Bc(a,b) = a*ctranspose(b)
|
||
|
||
"""
|
||
Ac_mul_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ Bᴴ``.
|
||
"""
|
||
Ac_mul_Bc(a,b) = ctranspose(a)*ctranspose(b)
|
||
|
||
"""
|
||
At_mul_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅B``.
|
||
"""
|
||
At_mul_B(a,b) = transpose(a)*b
|
||
|
||
"""
|
||
A_mul_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᵀ``.
|
||
"""
|
||
A_mul_Bt(a,b) = a*transpose(b)
|
||
|
||
"""
|
||
At_mul_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅Bᵀ``.
|
||
"""
|
||
At_mul_Bt(a,b) = transpose(a)*transpose(b)
|
||
|
||
# transposed divide
|
||
|
||
"""
|
||
Ac_rdiv_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / B``.
|
||
"""
|
||
Ac_rdiv_B(a,b) = ctranspose(a)/b
|
||
|
||
"""
|
||
A_rdiv_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A / Bᴴ``.
|
||
"""
|
||
A_rdiv_Bc(a,b) = a/ctranspose(b)
|
||
|
||
"""
|
||
Ac_rdiv_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / Bᴴ``.
|
||
"""
|
||
Ac_rdiv_Bc(a,b) = ctranspose(a)/ctranspose(b)
|
||
|
||
"""
|
||
At_rdiv_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / B``.
|
||
"""
|
||
At_rdiv_B(a,b) = transpose(a)/b
|
||
|
||
"""
|
||
A_rdiv_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A / Bᵀ``.
|
||
"""
|
||
A_rdiv_Bt(a,b) = a/transpose(b)
|
||
|
||
"""
|
||
At_rdiv_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / Bᵀ``.
|
||
"""
|
||
At_rdiv_Bt(a,b) = transpose(a)/transpose(b)
|
||
|
||
"""
|
||
Ac_ldiv_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``B``.
|
||
"""
|
||
Ac_ldiv_B(a,b) = ctranspose(a)\b
|
||
|
||
"""
|
||
A_ldiv_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᴴ``.
|
||
"""
|
||
A_ldiv_Bc(a,b) = a\ctranspose(b)
|
||
|
||
"""
|
||
Ac_ldiv_Bc(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᴴ``.
|
||
"""
|
||
Ac_ldiv_Bc(a,b) = ctranspose(a)\ctranspose(b)
|
||
|
||
"""
|
||
At_ldiv_B(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``B``.
|
||
"""
|
||
At_ldiv_B(a,b) = transpose(a)\b
|
||
|
||
"""
|
||
A_ldiv_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᵀ``.
|
||
"""
|
||
A_ldiv_Bt(a,b) = a\transpose(b)
|
||
|
||
"""
|
||
At_ldiv_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``Bᵀ``.
|
||
"""
|
||
At_ldiv_Bt(a,b) = At_ldiv_B(a,transpose(b))
|
||
|
||
"""
|
||
Ac_ldiv_Bt(A, B)
|
||
|
||
For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᵀ``.
|
||
"""
|
||
Ac_ldiv_Bt(a,b) = Ac_ldiv_B(a,transpose(b))
|
||
|
||
widen(x::T) where {T<:Number} = convert(widen(T), x)
|
||
|
||
# function pipelining
|
||
|
||
"""
|
||
|>(x, f)
|
||
|
||
Applies a function to the preceding argument. This allows for easy function chaining.
|
||
|
||
```jldoctest
|
||
julia> [1:5;] |> x->x.^2 |> sum |> inv
|
||
0.01818181818181818
|
||
```
|
||
"""
|
||
|>(x, f) = f(x)
|
||
|
||
# function composition
|
||
|
||
"""
|
||
f ∘ g
|
||
|
||
Compose functions: i.e. `(f ∘ g)(args...)` means `f(g(args...))`. The `∘` symbol can be
|
||
entered in the Julia REPL (and most editors, appropriately configured) by typing `\\circ<tab>`.
|
||
Example:
|
||
|
||
```jldoctest
|
||
julia> map(uppercase∘hex, 250:255)
|
||
6-element Array{String,1}:
|
||
"FA"
|
||
"FB"
|
||
"FC"
|
||
"FD"
|
||
"FE"
|
||
"FF"
|
||
```
|
||
"""
|
||
∘(f, g) = (x...)->f(g(x...))
|
||
|
||
|
||
"""
|
||
!f::Function
|
||
|
||
Predicate function negation: when the argument of `!` is a function, it returns a
|
||
function which computes the boolean negation of `f`. Example:
|
||
|
||
```jldoctest
|
||
julia> str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε"
|
||
"∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε"
|
||
|
||
julia> filter(isalpha, str)
|
||
"εδxyδfxfyε"
|
||
|
||
julia> filter(!isalpha, str)
|
||
"∀ > 0, ∃ > 0: |-| < ⇒ |()-()| < "
|
||
```
|
||
"""
|
||
!(f::Function) = (x...)->!f(x...)
|
||
|
||
# some operators not defined yet
|
||
global //, >:, <|, hcat, hvcat, ⋅, ×, ∈, ∉, ∋, ∌, ⊆, ⊈, ⊊, ∩, ∪, √, ∛
|
||
|
||
this_module = current_module()
|
||
baremodule Operators
|
||
|
||
export
|
||
!,
|
||
!=,
|
||
!==,
|
||
===,
|
||
xor,
|
||
%,
|
||
÷,
|
||
&,
|
||
*,
|
||
+,
|
||
-,
|
||
/,
|
||
//,
|
||
<,
|
||
<:,
|
||
>:,
|
||
<<,
|
||
<=,
|
||
==,
|
||
>,
|
||
>=,
|
||
≥,
|
||
≤,
|
||
≠,
|
||
>>,
|
||
>>>,
|
||
\,
|
||
^,
|
||
|,
|
||
|>,
|
||
<|,
|
||
~,
|
||
⋅,
|
||
×,
|
||
∈,
|
||
∉,
|
||
∋,
|
||
∌,
|
||
⊆,
|
||
⊈,
|
||
⊊,
|
||
∩,
|
||
∪,
|
||
√,
|
||
∛,
|
||
⊻,
|
||
∘,
|
||
colon,
|
||
hcat,
|
||
vcat,
|
||
hvcat,
|
||
getindex,
|
||
setindex!,
|
||
transpose,
|
||
ctranspose
|
||
|
||
import ..this_module: !, !=, xor, %, ÷, &, *, +, -,
|
||
/, //, <, <:, <<, <=, ==, >, >=, >>, >>>,
|
||
<|, |>, \, ^, |, ~, !==, ===, >:, colon, hcat, vcat, hvcat, getindex, setindex!,
|
||
transpose, ctranspose,
|
||
≥, ≤, ≠, ⋅, ×, ∈, ∉, ∋, ∌, ⊆, ⊈, ⊊, ∩, ∪, √, ∛, ⊻, ∘
|
||
|
||
end
|