Mercurial > repos > public > sbplib_julia
changeset 476:1b9af062ba2c feature/outer_product
Merge in default
author | Jonatan Werpers <jonatan@werpers.com> |
---|---|
date | Mon, 02 Nov 2020 21:34:33 +0100 |
parents | 2c0e76d5832d (diff) 3041f8578bba (current diff) |
children | 79a88269d7d0 |
files | test/testLazyTensors.jl |
diffstat | 2 files changed, 87 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/LazyTensors/lazy_tensor_operations.jl Mon Nov 02 21:33:35 2020 +0100 +++ b/src/LazyTensors/lazy_tensor_operations.jl Mon Nov 02 21:34:33 2020 +0100 @@ -279,3 +279,54 @@ flatten_tuple(t::NTuple{N, Number} where N) = t flatten_tuple(t::Tuple) = ((flatten_tuple.(t)...)...,) # simplify? flatten_tuple(ts::Vararg) = flatten_tuple(ts) + + +""" + LazyOuterProduct(tms...) + +Creates a `TensorComposition` for the outerproduct of `tms...`. +This is done by separating the outer product into regular products of outer products involving only identity mappings and one non-identity mapping. + +First let +```math +A = A_{I,J} +B = B_{M,N} +C = C_{P,Q} +``` + +where ``I``, ``M``, ``P`` are multi-indexes for the ranges of ``A``, ``B``, ``C``, and ``J``, ``N``, ``Q`` are multi-indexes of the domains. + +We use ``⊗`` to denote the outer product +```math +(A⊗B)_{IM,JN} = A_{I,J}B_{M,N} +``` + +We note that +```math +A⊗B⊗C = (A⊗B⊗C)_{IMP,JNQ} = A_{I,J}B_{M,N}C_{P,Q} +``` +And that +```math +A⊗B⊗C = (A⊗I_{|M|}⊗I_{|P|})(I_{|J|}⊗B⊗I_{|P|})(I_{|J|}⊗I_{|N|}⊗C) +``` +where |.| of a multi-index is a vector of sizes for each dimension. ``I_v`` denotes the identity tensor of size ``v[i]`` in each direction +To apply ``A⊗B⊗C`` we evaluate + +(A⊗B⊗C)v = [(A⊗I_{|M|}⊗I_{|P|}) [(I_{|J|}⊗B⊗I_{|P|}) [(I_{|J|}⊗I_{|N|}⊗C)v]]] +""" +function LazyOuterProduct end +export LazyOuterProduct + +function LazyOuterProduct(tm1::TensorMapping{T}, tm2::TensorMapping{T}) where T + itm1 = InflatedTensorMapping(tm1, IdentityMapping{T}(range_size(tm2))) + itm2 = InflatedTensorMapping(IdentityMapping{T}(domain_size(tm1)),tm2) + + return itm1∘itm2 +end + +LazyOuterProduct(tms::Vararg{TensorMapping}) = foldl(LazyOuterProduct, tms) + +⊗(a::TensorMapping, b::TensorMapping) = LazyOuterProduct(a,b) +export ⊗ + +# TBD: Should we implement simplifications for outer products of LazyIdentities other LazyIdentities or Inflated tensormappings?
--- a/test/testLazyTensors.jl Mon Nov 02 21:33:35 2020 +0100 +++ b/test/testLazyTensors.jl Mon Nov 02 21:34:33 2020 +0100 @@ -398,4 +398,40 @@ @test LazyTensors.flatten_tuple(((1,2),(3,4),(5,),6)) == (1,2,3,4,5,6) end + +@testset "LazyIdentityOuterProduct" begin + struct ScalingOperator{T,D} <: TensorMapping{T,D,D} + λ::T + size::NTuple{D,Int} + end + + LazyTensors.apply(m::ScalingOperator{T,D}, v, I::Vararg{Index,D}) where {T,D} = m.λ*v[I] + LazyTensors.range_size(m::ScalingOperator) = m.size + LazyTensors.domain_size(m::ScalingOperator) = m.size + + A = ScalingOperator(2.0, (5,)) + B = ScalingOperator(3.0, (3,)) + C = ScalingOperator(5.0, (3,2)) + + AB = LazyOuterProduct(A,B) + @test AB isa TensorMapping{T,2,2} where T + @test range_size(AB) == (5,3) + @test domain_size(AB) == (5,3) + + v = rand(range_size(AB)...) + @test AB*v == 6*v + + ABC = LazyOuterProduct(A,B,C) + + @test ABC isa TensorMapping{T,4,4} where T + @test range_size(ABC) == (5,3,3,2) + @test domain_size(ABC) == (5,3,3,2) + + @test A⊗B == AB + @test A⊗B⊗C == ABC + + # TODO: Include some tests where the domain has different size and dimension + end + +end