-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 59 coerce #95
Issue 59 coerce #95
Changes from all commits
38f1a35
f8c556d
0650afa
726475c
a285d29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# Copyright 2014, 2015 Jonas Adler | ||
# | ||
# This file is part of ODL. | ||
# | ||
# ODL is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# ODL is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with ODL. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
"""Operators to cast between spaces.""" | ||
|
||
# Imports for common Python 2/3 codebase | ||
from __future__ import print_function, division, absolute_import | ||
from future import standard_library | ||
standard_library.install_aliases() | ||
from builtins import super | ||
|
||
from odl.space.base_ntuples import FnBase | ||
from odl.discr.lp_discr import DiscreteLp | ||
from odl.set.pspace import ProductSpace | ||
from odl.operator.operator import Operator | ||
|
||
__all__ = ('Embedding', 'EmbeddingFnInFn', 'EmbeddingPowerSpaceInFn', | ||
'EmbeddingFnInPowerSpace') | ||
|
||
|
||
class Embedding(Operator): | ||
"""An operators to cast between spaces.""" | ||
|
||
# TODO: is this needed? | ||
|
||
def __init__(self, origin, target): | ||
super().__init__(origin, target) | ||
|
||
|
||
class EmbeddingFnInFn(Embedding): | ||
""" Embed a `FnBase` space into another """ | ||
|
||
def __init__(self, origin, target): | ||
assert isinstance(origin, FnBase) | ||
assert isinstance(target, FnBase) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if we could replace all our obvious type checks with asserts? At least when the docstring says what you can provide, the error message is easy to relate to the error source. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about this before, but I'm not quite sure. Anytime a user could give the wrong input we should give an error imo. Asserts are to make sure we havnt made any algorithmic error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just tried it in the console. |
||
|
||
super().__init__(origin, target) | ||
|
||
def _apply(self, x, out): | ||
out[:] = x.asflatarray() | ||
|
||
def _call(self, x): | ||
return self.range.element(x.asflatarray()) | ||
|
||
@property | ||
def adjoint(self): | ||
return EmbeddingFnInFn(self.range, self.domain) | ||
|
||
|
||
class EmbeddingDiscreteLpInDiscreteLp(Embedding): | ||
""" Embed a `DiscreteLp` space into another """ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This operator could also handle extension by zero (constant? nearest value?) to a larger domain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only with some strict constraints, for example the values need to coicide in some points at least approximately if we want to do this on a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a But in general, it's hard to get around using restriction and extension, and then one can implement a much wider range of operations going beyond pure embedding, e.g. subsample by interpolation. With vectorization, this should not be too inefficient. The good part here is also that the interpolation comes along with some options for how to handle values outside. Conclusion: alright, keep it simple and implement the fancy stuff in a different operator. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. |
||
def __init__(self, origin, target): | ||
assert isinstance(origin, DiscreteLp) | ||
assert isinstance(target, DiscreteLp) | ||
assert origin.grid.shape == target.grid.shape | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should only be possible if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about that, embedding (to me) means, "Do as your told and ignore the consequences". Kindoff like how mathematicians often "identify" things with others. Perhaps the vectors given to this will only be in a subspace where it still works? I think we need a way for users to "force" this through. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This guy could take a parameter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sure, but I'd default it to False.
Then this needs to be renamed. Very few of these are actually to superspaces, and the adjoint would then never be defined (which obviously isn't that useful). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's a projection then. In that case I'm good with not checking the exponent. |
||
|
||
super().__init__(origin, target) | ||
|
||
def _apply(self, x, out): | ||
out[:] = x.asarray() | ||
|
||
def _call(self, x): | ||
return self.range.element(x.asarray()) | ||
|
||
@property | ||
def adjoint(self): | ||
return EmbeddingDiscreteLpInDiscreteLp(self.range, self.domain) | ||
|
||
|
||
class EmbeddingPowerSpaceInFn(Embedding): | ||
""" Embed a `PowerSpace` of `FnBase` space into a `FnBase` """ | ||
|
||
def __init__(self, origin, target): | ||
# TODO: tests goes here | ||
|
||
super().__init__(origin, target) | ||
|
||
def _apply(self, x, out): | ||
out[:] = x.asflatarray() | ||
|
||
def _call(self, x): | ||
return self.range.element(x.asflatarray()) | ||
|
||
@property | ||
def adjoint(self): | ||
return EmbeddingFnInPowerSpace(self.range, self.domain) | ||
|
||
|
||
class EmbeddingFnInPowerSpace(Embedding): | ||
""" Embed a `FnBase` into `PowerSpace` of `FnBase`'s""" | ||
|
||
def __init__(self, origin, target): | ||
# TODO: tests goes here | ||
|
||
super().__init__(origin, target) | ||
|
||
def _apply(self, x, out): | ||
index = 0 | ||
for sub_vec in out: | ||
sub_vec[:] = x.asflatarray(index, index + sub_vec.size) | ||
index += sub_vec.size | ||
|
||
def _call(self, x): | ||
out = self.range.element() | ||
index = 0 | ||
for sub_vec in out: | ||
sub_vec[:] = x.asflatarray(index, index + sub_vec.size) | ||
index += sub_vec.size | ||
return out | ||
|
||
@property | ||
def adjoint(self): | ||
return EmbeddingPowerSpaceInFn(self.range, self.domain) | ||
|
||
|
||
if __name__ == '__main__': | ||
from doctest import testmod, NORMALIZE_WHITESPACE | ||
testmod(optionflags=NORMALIZE_WHITESPACE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small thing:
Into
instead ofIn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!