Commit 42150f8f authored by Martin Reinecke's avatar Martin Reinecke
Browse files

Merge branch 'model_documentation' into 'NIFTy_5'

Model documentation

See merge request ift/nifty-dev!8
parents d940e72f f4164d98
......@@ -21,9 +21,9 @@ from ..sugar import makeOp
from .model import Model
def _joint_position(op1, op2):
a = op1.position._val
b = op2.position._val
def _joint_position(model1, model2):
a = model1.position._val
b = model2.position._val
# Note: In python >3.5 one could do {**a, **b}
ab = a.copy()
ab.update(b)
......@@ -31,57 +31,78 @@ def _joint_position(op1, op2):
class ScalarMul(Model):
def __init__(self, factor, op):
# TODO op -> model
super(ScalarMul, self).__init__(op.position)
"""Class representing a model multiplied by a scalar factor."""
def __init__(self, factor, model):
super(ScalarMul, self).__init__(model.position)
# TODO -> floating
if not isinstance(factor, (float, int)):
raise TypeError
self._op = op
self._model = model
self._factor = factor
self._value = self._factor * self._op.value
self._gradient = self._factor * self._op.gradient
self._value = self._factor * self._model.value
self._gradient = self._factor * self._model.gradient
def at(self, position):
return self.__class__(self._factor, self._op.at(position))
return self.__class__(self._factor, self._model.at(position))
class Add(Model):
def __init__(self, position, op1, op2):
"""Class representing the sum of two models."""
def __init__(self, position, model1, model2):
super(Add, self).__init__(position)
self._op1 = op1.at(position)
self._op2 = op2.at(position)
self._model1 = model1.at(position)
self._model2 = model2.at(position)
self._value = self._op1.value + self._op2.value
self._gradient = self._op1.gradient + self._op2.gradient
self._value = self._model1.value + self._model2.value
self._gradient = self._model1.gradient + self._model2.gradient
@staticmethod
def make(op1, op2):
position = _joint_position(op1, op2)
return Add(position, op1, op2)
def make(model1, model2):
"""Build the sum of two models.
Parameters
----------
model1: Model
First model.
model2: Model
Second model
"""
position = _joint_position(model1, model2)
return Add(position, model1, model2)
def at(self, position):
return self.__class__(position, self._op1, self._op2)
return self.__class__(position, self._model1, self._model2)
class Mul(Model):
def __init__(self, position, op1, op2):
"""Class representing the pointwise product of two models."""
def __init__(self, position, model1, model2):
super(Mul, self).__init__(position)
self._op1 = op1.at(position)
self._op2 = op2.at(position)
self._model1 = model1.at(position)
self._model2 = model2.at(position)
self._value = self._op1.value * self._op2.value
self._gradient = (makeOp(self._op1.value) * self._op2.gradient +
makeOp(self._op2.value) * self._op1.gradient)
self._value = self._model1.value * self._model2.value
self._gradient = (makeOp(self._model1.value) * self._model2.gradient +
makeOp(self._model2.value) * self._model1.gradient)
@staticmethod
def make(op1, op2):
position = _joint_position(op1, op2)
return Mul(position, op1, op2)
def make(model1, model2):
"""Build the pointwise product of two models.
Parameters
----------
model1: Model
First model.
model2: Model
Second model
"""
position = _joint_position(model1, model2)
return Mul(position, model1, model2)
def at(self, position):
return self.__class__(position, self._op1, self._op2)
return self.__class__(position, self._model1, self._model2)
......@@ -15,11 +15,25 @@
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
from .model import Model
class Constant(Model):
"""A sky model with a constant (multi-)field as value.
Parameters
----------
position : Field or MultiField
The current position in parameter space.
constant : Field
The value of the model.
Note
----
Since there is no model-function associated:
- Position has no influence on value.
- There is no gradient.
"""
# TODO Remove position
def __init__(self, position, constant):
super(Constant, self).__init__(position)
......
......@@ -21,8 +21,20 @@ from .model import Model
class LinearModel(Model):
def __init__(self, inp, lin_op):
"""
Computes lin_op(inp) where lin_op is a Linear Operator
"""Computes lin_op(inp) where lin_op is a Linear Operator
Parameters
----------
inp : Model
lin_op : LinearOperator
linear function to be applied to model
Returns
-------
Model with linear Operator applied:
- Model.value = LinOp (inp.value) [key-wise]
- Gradient = LinOp * inp.gradient
"""
from ..operators.linear_operator import LinearOperator
super(LinearModel, self).__init__(inp.position)
......
......@@ -26,6 +26,15 @@ class LocalModel(Model):
def __init__(self, inp, nonlinearity):
"""
Computes nonlinearity(inp)
- LocalModel.value = nonlinearity(value) (pointwise)
- LocalModel.gradient = Outer Product of gradients
Parameters
----------
inp : Model
The model for which the nonlinarity will be applied.
nonlinearity: Function
The nonlinearity to be applied to model.
"""
super(LocalModel, self).__init__(inp.position)
self._inp = inp
......
......@@ -24,22 +24,66 @@ from ..utilities import NiftyMetaBase
class Model(NiftyMetaBase()):
"""
The Model object is an implementation of a * which knows:
- position in parameterspace. (Field, MulitField)
- value according to its modelfunction A. A(position)
- gradient of the modelfunction at the current position.
Parameters
----------
position : Field, MulitField
The input parameter of the model
Notes
-----
An instance of the model class knows its position, value and gradient.
One can 'jump' to a new position, with the help of the 'at' method, whereby
one automatically gets the value and gradient of the model. The 'at' method
creates a new instance of the class.
"""
def __init__(self, position):
self._position = position
def at(self, position):
""" Returns a new Model object, initialized at `position`.
Parameters
----------
position : Field or MultiField
Location in parameter space for the new Model object.
Returns
-------
Model
Model object at new position.
"""
raise NotImplementedError
@property
def position(self):
"""
Field or MultiField: selected location in parameter space.
The location in parameter space where value and gradient are
evaluated.
"""
return self._position
@property
def value(self):
"""
Field or MultiField: value of the model.
The value of the model at given `position`.
"""
return self._value
@property
def gradient(self):
"""
LinearOperator : The derivative of the model at given `position`.
"""
return self._gradient
def __getitem__(self, key):
......
......@@ -23,6 +23,7 @@ from .model import Model
class MultiModel(Model):
""" """
def __init__(self, model, key):
# TODO Rewrite it such that it takes a dictionary as input. Just like MultiFields.
super(MultiModel, self).__init__(model.position)
......
......@@ -21,8 +21,12 @@ from .model import Model
class Variable(Model):
"""
Returns the MultiField.
"""Changes (Multi-)Field to be a Variable model.
Parameters
----------
position : Field or MultiField
The current position in parameter space.
"""
def __init__(self, position):
super(Variable, self).__init__(position)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment