Skip to content
This repository has been archived by the owner on Jul 19, 2023. It is now read-only.

Linear Combinations of Operators #55

Merged
merged 10 commits into from
Mar 6, 2018

Conversation

MSeeker1340
Copy link
Contributor

Adds expm and norm methods for linear combinations of DiffEqArrayOperator and derivative operators. Also includes a normbound method that computes a upper bound to the norm using triangle inequality. normbound(A,Inf) can serve as an efficient estimate for the operator norm in applications where the exact norm is not desired (for example in error estimation in Krylov methods), because it is easy to calculate the Inf norm for derivative operators.

In addition, fixes an error in norm for DiffEqArrayOperator (it now takes into account the coefficient too) and adds a test set for DiffEqArrayOperator.

The efficient full method for linear combinations is currently bugged as Julia's type dispatching will always default to the full method defined in LinearMaps.jl.

Not sure where to put the functions for the linear combination though, since it handles both DiffEqArrayOperator and derivative operators.

@codecov
Copy link

codecov bot commented Mar 5, 2018

Codecov Report

❗ No coverage uploaded for pull request base (master@396f7ea). Click here to learn what that means.
The diff coverage is 40%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master      #55   +/-   ##
=========================================
  Coverage          ?   68.98%           
=========================================
  Files             ?        9           
  Lines             ?      790           
  Branches          ?        0           
=========================================
  Hits              ?      545           
  Misses            ?      245           
  Partials          ?        0
Impacted Files Coverage Δ
...erivative_operators/abstract_operator_functions.jl 68.53% <0%> (ø)
src/array_operator.jl 34.37% <100%> (ø)
src/operator_combination.jl 38.46% <38.46%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 396f7ea...590acb6. Read the comment docs.

@MSeeker1340 MSeeker1340 changed the title Linear Combinations of Operators [WIP] Linear Combinations of Operators Mar 5, 2018
@MSeeker1340
Copy link
Contributor Author

MSeeker1340 commented Mar 5, 2018

Seems I still haven't covered everything thoroughly...

To calculate caching phi in NorsettEuler I need to evaluate

expA = expm(A*dt)
phi1 = ((expA-I)/A)

and we cannot divide by a derivative operator at the moment. So there's more work to be done.

Base.expm(A::LinearCombination) = expm(full(A))

Base.norm(A::IdentityMap{T}, p::Real=2) where T = real(one(T))
Base.norm(A::LinearCombination, p::Real=2) = norm(full(A), p)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lazy way to do normest2 which will be required when A doesn't fit into memory, but we can handle that later. Probably worth a comment and an issue though.

@MSeeker1340
Copy link
Contributor Author

MSeeker1340 commented Mar 5, 2018

I'll drop the WIP flag once things check out on the OrdinaryDiffEq end.

Also, should we explicitly call full at the caching step? i.e. instead of

expA = expm(A*dt)
phi1 = (expA - I) / A

use

fullA = full(A)
expA = expm(fullA*dt)
phi1 = (expA - I) / fullA

This way we will avoid a lot of potential problems for future caching methods.

@ChrisRackauckas
Copy link
Member

Also, should we explicitly call full at the caching step?

Yes, for the cached ones we know we have to full so we might as well do it right before the computations.

@MSeeker1340 MSeeker1340 changed the title [WIP] Linear Combinations of Operators Linear Combinations of Operators Mar 5, 2018
@MSeeker1340
Copy link
Contributor Author

All set. I'll do a PR on OrdinaryDiffEq after this is updated.

end
out
end
Base.full(L::DiffEqArrayOperator) = full(L.A) * L.α.coeff
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.* this so that way it's compatible with coefficient arrays. That'll come up in space-dependent coefficients and quasi-linear PDEs.

Base.expm(A::AbstractDerivativeOperator{T}) where T = expm(full(A))
Base.:/(A::AbstractVecOrMat, B::AbstractDerivativeOperator) = A / full(B)
Base.:/(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = full(A) / B
# Base.:\ is also defined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC isn't / defined in terms of \ with a transpose? It may be better to do that one directly. I would use @which to dive into the Base code and see how / is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented out this portion and found that

using DiffEqOperators
N = 20
A = DerivativeOperator{Float64}(2,2,1.0,N,:Dirichlet0,:Dirichlet0)
mat = rand(N,N)

@which A / mat
no method found for the specified argument types

@which mat' \ A'
\(x, y) at operators.jl:457

The definition is

\(x,y) = (y'/x')'

So Julia does in fact define \ in terms of / for generic types. However for regular matrices the relationship is inverted:

# In linalg\generic.jl:820
(/)(A::AbstractVecOrMat, B::AbstractVecOrMat) = (B' \ A')'

Do you think I should define / using this convention, or just go with the generic one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might need both. The transpose operator will be hard to do in general, and right now I think it's a no-op which only holds for some BCs and since we have the operator as n x n. Transpose on the dense matrix will always work though.

@ChrisRackauckas
Copy link
Member

Small changes I missed last time, then this looks good to go.

Base.expm(A::AbstractDerivativeOperator{T}) where T = expm(full(A))
Base.:\(A::AbstractVecOrMat, B::AbstractDerivativeOperator) = A \ full(B)
Base.:\(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = full(A) \ B
Base.:/(A::AbstractVecOrMat, B::AbstractDerivativeOperator) = (B' \ A')'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These transposes might be incorrect because they are just implemented as a no-op. Sorry if I was unclear before. I think you should just full and /, or does the generic version but full before transpose.

@ChrisRackauckas ChrisRackauckas mentioned this pull request Mar 6, 2018
@ChrisRackauckas ChrisRackauckas merged commit 3197ca5 into SciML:master Mar 6, 2018
@MSeeker1340 MSeeker1340 deleted the linear-combination branch March 6, 2018 16:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants