Expressions
With StructuredOptimization.jl
you can easily create mathematical expressions. Firstly, Variables must be defined: various Mappings can then be applied following the application of Functions and constraints to create the Term
s that define the optimization problem.
Variables
Creating Variables
StructuredOptimization.Variable
— TypeVariable([T::Type,] dims...)
Returns a Variable
of dimension dims
initialized with an array of all zeros.
Variable(x::AbstractArray)
Returns a Variable
of dimension size(x)
initialized with x
StructuredOptimization.jl
supports complex variables. It is possible to create them by specifying the type Variable(Complex{Float64}, 10)
or by initializing them with a complex array Variable(randn(10)+im*randn(10))
.
Utilities
Base.:~
— Function~(x::Variable)
Returns the Array
of the variable x
Base.size
— Functionsize(x::Variable, [dim...])
Like size(A::AbstractArray, [dims...])
returns the tuple containing the dimensions of the variable x
.
Base.eltype
— Functioneltype(x::Variable)
Like eltype(x::AbstractArray)
returns the type of the elements of x
.
Summing expressions
Base.:+
— Function+(ex1::AbstractExpression, ex2::AbstractExpression)
Add two expressions.
Examples
julia> x,y = Variable(5), Variable(5)
(Variable(Float64, (5,)), Variable(Float64, (5,)))
julia> ex1 = x+y
julia> z = Variable(2)
Variable(Float64, (2,))
julia> ex2 = randn(5,2)*z
Notice that in order for two expressions to be added toghether their associated AbstractOperator
must have the same codomain:
julia> operator(ex1)
[I,I] ℝ^5 ℝ^5 -> ℝ^5
julia> operator(ex2)
▒ ℝ^2 -> ℝ^5
julia> ex3 = ex1 + ex2
It is also possible to use broadcasted addition:
julia> z = Variable(1)
Variable(Float64, (1,))
julia> ex3.+z
+(ex::AbstractExpression, b::Union{AbstractArray,Number})
Add a scalar or an Array
to an expression:
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = x+4
Notice that in order to add an array to ex
, b
must belong to the codomain of the associated AbstractOperator
of ex
.
julia> b = randn(10);
julia> size(b), eltype(b)
((10,), Float64)
julia> size(affine(ex),1), codomainType(affine(ex))
((10,), Float64)
julia> ex + b
Multiplying expressions
Base.:*
— Function*(A::AbstractOperator, ex::AbstractExpression)
Multiply an 'AbstractExpressionby an
AbstractOperator`.
Example
julia> A = FiniteDiff(Float64, (10,))
δx ℝ^10 -> ℝ^9
julia> x = Variable(10);
julia> ex = A*x;
julia> B = DCT(9)
ℱc ℝ^9 -> ℝ^9
julia> ex2 = B*ex;
julia> affine(ex2)
ℱc*δx ℝ^10 -> ℝ^9
*(A::AbstractMatrix, ex::AbstractExpression)
Multiply an AbstractExpression
by an AbstractMatrix
.
julia> A = randn(10,5);
julia> x = Variable(5)
Variable(Float64, (5,))
julia> A*x
Other types of multiplications are also possible:
- left array multiplication
julia> X = Variable(10,5)
Variable(Float64, (10, 5))
julia> X*randn(5,6)
- scalar multiplication:
julia> π*X
- elementwise multiplication:
julia> randn(10,5).*X
*(A::AbstractExpression, ex::AbstractExpression)
Multiply an AbstractExpression
by another AbstractExpression
.
Examples
julia> W1 = Variable(10,5)
Variable(Float64, (10, 5))
julia> W2 = Variable(5,15)
Variable(Float64, (5, 15))
julia> ex = W1*σ(W2);
julia> affine(ex)
I*σ ℝ^(10, 5) ℝ^(5, 15) -> ℝ^(10, 15)
.*(A::AbstractExpression, ex::AbstractExpression)
Elementwise multiplication between AbstractExpression
(i.e. Hadamard product).
Mappings
As shown in the Quick tutorial guide it is possible to apply different mappings to the variables using a simple syntax.
Alternatively, as shown in Multiplying expressions, it is possible to define the mappings using AbstractOperators.jl
and to apply them to the variable (or expression) through multiplication.
Basic mappings
Base.getindex
— Functiongetindex(x::AbstractExpression, dims...)
Slices the codomain of ex
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> getindex(x,1:4)
julia> X = Variable(10,4)
Variable(Float64, (10, 4))
julia> X[:,1:3]
Base.reshape
— Functionreshape(x::AbstractExpression, dims...)
Reshapes the codomain of the expression.
Example
julia> A,b = randn(10,3), randn(10);
julia> reshape(A*x-b,2,5)
DSP mappings
AbstractFFTs.fft
— Functionfft(x::AbstractExpression)
Applies the Fourier transform. See documentation for Base.fft
and AbstractOperator.DFT
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = fft(x)
julia> operator(ex)
ℱ ℝ^10 -> ℂ^10
AbstractFFTs.ifft
— Functionifft(x::AbstractExpression)
Applies the inverse Fourier transform. See documentation for Base.ifft
and AbstractOperator.IDFT
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = ifft(x)
julia> operator(ex)
ℱ⁻¹ ℝ^10 -> ℂ^10
AbstractFFTs.rfft
— Functionrfft(x::AbstractExpression, [, dims] )
Applies the Fourier transform exploiting the conjugate symmetry. See documentation for Base.rfft
and AbstractOperator.RDFT
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = rfft(x)
julia> operator(ex)
ℱ ℝ^10 -> ℂ^6
AbstractFFTs.irfft
— Functionirfft(x::AbstractExpression, d, [, dims] )
Applies the inverse Fourier transform exploiting the conjugate symmetry.
d
must indicate the length of the real codomain.
See documentation for Base.irfft
and AbstractOperator.IRDFT
.
Example
julia> x = Variable(Complex{Float64}, 10)
Variable(Float64, (10,))
julia> ex = irfft(x,19)
julia> operator(ex)
ℱ⁻¹ ℂ^10 -> ℝ^19
FFTW.dct
— Functiondct(x::AbstractExpression)
Applies the discrete cosine transform. See documentation for Base.dct
and AbstractOperator.DCT
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = dct(x)
julia> operator(ex)
ℱc ℝ^10 -> ℝ^10
FFTW.idct
— Functionidct(x::AbstractExpression)
Applies the inverse discrete cosine transform. See documentation for Base.idct
and AbstractOperator.IDCT
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = idct(x)
julia> operator(ex)
ℱc⁻¹ ℝ^10 -> ℝ^10
DSP.conv
— Functionconv(x::AbstractExpression, h::AbstractVector)
Perform discrete convolution with h
. See documentation for Base.conv
and AbstractOperator.Conv
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = conv(x, randn(5))
julia> operator(ex)
★ ℝ^10 -> ℝ^14
DSP.xcorr
— Functionxcorr(x::AbstractExpression, h::AbstractVector)
Performs the cross correlation of the codomain of ex
with h
. See documentation for Base.xcorr
and AbstractOperator.Xcorr
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = xcorr(x, randn(5))
julia> operator(ex)
◎ ℝ^10 -> ℝ^19
DSP.filt
— Functionfilt(x::AbstractExpression, b::AbstractVector, [a::AbstractVector])
Filter with the finite impulse response (FIR) b
. Alternatively infinite impulse responses filters (IIR) can be used as well by specifying the coefficients a
.
See documentation for Base.filt
and AbstractOperator.Filt
.
Example
julia> x = Variable(10)
Variable(Float64, (10,))
julia> ex = filt(x, [1.;0.;0.],[1.;0.;1.])
julia> operator(ex)
IIR ℝ^10 -> ℝ^10
julia> ex = filt(x, [1.;0.;0.])
julia> operator(ex)
FIR ℝ^10 -> ℝ^10
StructuredOptimization.mimofilt
— Functionmimofilt(X::AbstractExpression, B::Vector{AbstractVector}, [A::Vector{AbstractVector}])
Multiple-input multiple-output filter: like filt
but allows for multipule inputs.
where $\mathbf{y}_i$ and $\mathbf{x}_j$ are the $i$-th and $j$-th columns of the output Y
and input X
matrices respectively.
The filters $\mathbf{h}_{i,j}$ can be represented either by providing coefficients B
and A
(IIR) or B
alone (FIR). These coefficients must be given in a Vector
of Vector
s.
For example for a 3
by 2
MIMO system (i.e. size(X,2) == 3
inputs and size(Y,2) == 2
outputs) B
must be:
B = [b11, b12, b13, b21, b22, b23]
where bij
are vector containing the filter coeffients of h_{i,j}
.
See documentation of AbstractOperator.MIMOFilt
.
StructuredOptimization.zeropad
— Functionzeropad(x::AbstractExpression, zp::Tuple)
Performs zeropadding:
where zp
is a tuple containing the number of nonzero elements that are added in each dimension.
See documentation of AbstractOperator.ZeroPad
.
Finite differences mappings
StructuredOptimization.finitediff
— Functionfinitediff(X::AbstractExpression, dir = 1)
Performs the discretized gradient over the specified direction dir
obtained using forward finite differences.
Example
julia> X = Variable(10,10)
Variable(Float64, (10,10))
julia> ex = finitediff(X)
julia> operator(ex)
δx ℝ^(10, 10) -> ℝ^(9, 10)
julia> ex = finitediff(X,2)
julia> operator(ex)
δy ℝ^(10, 10) -> ℝ^(10, 9)
StructuredOptimization.variation
— Functionvariation(X::AbstractExpression)
Returns the variation of X
using forward finite differences. Specifically if X
is in ℝ^(n, m)
the codomain of variation(X)
will consist of ℝ^(n*m,2)
, having in the $i$-th column the vectorized gradient over the $i$-th direction.
See documentation of AbstractOperator.Variation
.
Example
julia> X = Variable(4,5,6)
Variable(Float64, (4,5,6))
julia> ex = variation(X)
julia> operator(ex)
Ʋ ℝ^(4, 5, 6) -> ℝ^(120, 3)
Nonlinear mappings
Base.sin
— Functionsin(x::AbstractExpression)
Sine function:
See documentation of AbstractOperator.Sin
.
Base.cos
— Functioncos(x::AbstractExpression)
Cosine function:
See documentation of AbstractOperator.Cos
.
Base.atan
— Functionatan(x::AbstractExpression)
Inverse tangent function:
See documentation of AbstractOperator.Atan
.
Base.tanh
— Functiontanh(x::AbstractExpression)
Hyperbolic tangent function:
See documentation of AbstractOperator.Tanh
.
Base.exp
— Functionexp(x::AbstractExpression)
Exponential function:
See documentation of AbstractOperator.Exp
.
StructuredOptimization.pow
— Functionpow(x::AbstractExpression, n)
Elementwise n
-th power of x
:
See documentation of AbstractOperator.Pow
.
StructuredOptimization.sigmoid
— Functionsigmoid(x::AbstractExpression, γ = 1.0)
σ(x::AbstractExpression, γ = 1.0)
Sigmoid function:
See documentation of AbstractOperator.Sigmoid
.
Utilities
It is possible to access the variables, mappings and displacement of an expression. Notice that these commands work also for the Term
s described in Functions and constraints.
StructuredOptimization.variables
— Functionvariables(ex::Expression)
Returns a tuple containing the Variable
s of expression ex
.
Example
julia> x,y = Variable(2),Variable(2);
julia> ex = x+y;
julia> variables(ex)
(Variable(Float64, (2,)), Variable(Float64, (2,)))
StructuredOptimization.operator
— Functionoperator(ex::Expression)
Returns the AbstractOperator
of expression ex
.
Example
julia> x = Variable(3)
Variable(Float64, (3,))
julia> ex = fft(x);
julia> operator(ex)
ℱ ℝ^3 -> ℂ^3
StructuredOptimization.affine
— Functionaffine(ex::Expression)
Returns the AbstractOperator
of expression ex
keeping any affine addition.
AbstractOperators.displacement
— Functiondisplacement(ex::Expression)
Returns the displacement of expression ex
.
Example
julia> x = Variable(3)
Variable(Float64, (3,))
julia> ex = fft(x)+[1.+im*2.;0.;3.+im*4];
julia> displacement(ex)
3-element Array{Complex{Float64},1}:
1.0+2.0im
0.0+0.0im
3.0+4.0im