Type Alias easy_ml::differentiation::RecordTensor
source · pub type RecordTensor<'a, T, S, const D: usize> = RecordContainer<'a, T, TensorView<(T, Index), S, D>, D>;
Expand description
Alias for succinctly referring to RecordContainers backed by a tensor.
Aliased Type§
struct RecordTensor<'a, T, S, const D: usize> { /* private fields */ }
Implementations§
source§impl<'a, T, const D: usize> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
impl<'a, T, const D: usize> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
sourcepub fn from_iter<I>(
shape: [(Dimension, usize); D],
iter: I
) -> Result<Self, InvalidRecordIteratorError<'a, T, D>>where
I: IntoIterator<Item = Record<'a, T>>,
pub fn from_iter<I>(
shape: [(Dimension, usize); D],
iter: I
) -> Result<Self, InvalidRecordIteratorError<'a, T, D>>where
I: IntoIterator<Item = Record<'a, T>>,
Given an iterator of records and a matching shape, collects them back into a RecordTensor.
This should generally be preferred over converting the iterator to a Vec of Records, since a Vec of Records has to store the WengertList reference for each individual record whereas a RecordTensor only stores it once.
However, since a RecordTensor only stores the WengertList once, this conversion will fail if there are different histories in the iterator. It also fails if the iterator is empty or doesn’t match the number of elements for the shape.
See also: elements
sourcepub fn from_iters<I, const N: usize>(
shape: [(Dimension, usize); D],
iter: I
) -> [Result<Self, InvalidRecordIteratorError<'a, T, D>>; N]
pub fn from_iters<I, const N: usize>( shape: [(Dimension, usize); D], iter: I ) -> [Result<Self, InvalidRecordIteratorError<'a, T, D>>; N]
Given an iterator of N record pairs and a matching shape, collects them back into N RecordTensors.
This should generally be preferred over converting the iterator to N Vecs of Records, since a Vec of Records has to store the WengertList reference for each individual record whereas a RecordTensor only stores it once.
However, since a RecordTensor only stores the WengertList once, this conversion will fail if there are different histories in the iterator. It also fails if the iterator is empty or doesn’t match the number of elements for the shape. Each failure due to different histories is seperate, if the ith elements in the records of the iterator have a consistent history but the jth elements do not then the ith result will be Ok but the jth will be Err.
See also: elements
source§impl<'a, T, const D: usize> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
impl<'a, T, const D: usize> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
sourcepub fn constants<S>(c: S) -> Selfwhere
S: TensorMut<T, D>,
pub fn constants<S>(c: S) -> Selfwhere
S: TensorMut<T, D>,
Creates multiple untracked Records which have no backing WengertList.
This is provided for using constants along with Records in operations.
For example with Y = X + 4
the computation graph could be conceived as many
Y[i,j]
nodes with parent nodes of X[i,j]
and 4 combined with the operation +
.
However there is no need to record the derivatives of a constant, so
instead the computation graph can be conceived as Y[i,j]
nodes each with a single
parent node of X[i,j]
and the unary operation of +4
.
sourcepub fn variables<S>(history: &'a WengertList<T>, x: S) -> Selfwhere
S: TensorMut<T, D>,
pub fn variables<S>(history: &'a WengertList<T>, x: S) -> Selfwhere
S: TensorMut<T, D>,
Creates multiple records backed by the provided WengertList.
The records cannot live longer than the WengertList, hence the following example does not compile
use easy_ml::differentiation::RecordTensor;
use easy_ml::differentiation::WengertList;
use easy_ml::tensors::Tensor;
let record = {
let list = WengertList::new();
RecordTensor::variables(
&list,
Tensor::from([("r", 2), ("c", 2)], vec![ 1.0, 2.0, 3.0, 4.0 ])
)
}; // list no longer in scope
source§impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
sourcepub fn elements(&self) -> usize
pub fn elements(&self) -> usize
Returns the number of elements stored by this container’s source.
For a 2 x 3 Tensor, this would return 6, and for a 2 x 3 x 4 Tensor this would return 24 and so on.
see also dimensions::elements
sourcepub fn from_existing(
history: Option<&'a WengertList<T>>,
numbers: TensorView<(T, Index), S, D>
) -> Self
pub fn from_existing( history: Option<&'a WengertList<T>>, numbers: TensorView<(T, Index), S, D> ) -> Self
Creates a container from constants/variables directly, most likely obtained by getting a tensor view of an existing container. The inputs are not checked for validity. It is possible to pass in the wrong Wengert list here or even numbers with indexes that aren’t tracked on the WengertList.
It is recommended to use this constructor only in conjunction with
resizing or masking an existing container and not for creating new variables. Any variables
created outside of RecordContainer::variables
would have to be manually added to the
correct Wengert list, and any arithmetic operations would also need tracking correctly.
use easy_ml::differentiation::RecordTensor;
use easy_ml::differentiation::WengertList;
use easy_ml::tensors::Tensor;
use easy_ml::tensors::views::{TensorView, TensorRange};
let list = WengertList::new();
let x = RecordTensor::variables(
&list,
Tensor::from_fn([("x", 2), ("y", 2)], |[r, c]| ((r + 3) * (c + 2)) as f64)
);
// oh no wrong shape!
let fixed = TensorView::from(TensorRange::from(x, [("y", 0..1)]).unwrap()); // we can unwrap here because we know the range is valid
let x = RecordTensor::from_existing(Some(&list), fixed);
assert_eq!([("x", 2), ("y", 1)], x.shape());
sourcepub fn rename_view(
self,
dimensions: [Dimension; D]
) -> RecordTensor<'a, T, TensorRename<(T, Index), S, D>, D>
pub fn rename_view( self, dimensions: [Dimension; D] ) -> RecordTensor<'a, T, TensorRename<(T, Index), S, D>, D>
Returns a record tensor with the dimension names of the shape renamed to the provided dimensions. The data of this container and the dimension lengths and order remain unchanged.
This is a shorthand for constructing the RecordTensor via manipulating this TensorView. See
RecordTensor::from_existing
.
§Panics
If a dimension name is not unique
use easy_ml::differentiation::RecordTensor;
use easy_ml::differentiation::WengertList;
use easy_ml::tensors::Tensor;
use easy_ml::tensors::views::{TensorView, TensorRename};
let list = WengertList::new();
let x = RecordTensor::variables(
&list,
Tensor::from_fn([("x", 2), ("y", 2)], |[r, c]| ((r + 3) * (c + 2)) as f64)
);
// oh no wrong dimension names!
let x = x.rename_view(["a", "b"]);
assert_eq!([("a", 2), ("b", 2)], x.shape());
sourcepub fn view(&self) -> TensorView<(T, Index), &RecordTensor<'a, T, S, D>, D>
pub fn view(&self) -> TensorView<(T, Index), &RecordTensor<'a, T, S, D>, D>
Returns a TensorView of this record container, both the T
for each record element and
also the index for that record’s entry in the WengertList. These can be parsed back into
a RecordTensor with from_existing
or individually into
Records with Record::from_existing
to continue tracking
numerical operations on the data.
sourcepub fn index_by(
&self,
dimensions: [Dimension; D]
) -> TensorAccess<(T, Index), &RecordTensor<'a, T, S, D>, D>
pub fn index_by( &self, dimensions: [Dimension; D] ) -> TensorAccess<(T, Index), &RecordTensor<'a, T, S, D>, D>
Returns a TensorAccess which can be indexed in the order of the supplied dimensions
to read values from this record container, both the T
for each record element and
also the index for that record’s entry in the WengertList. These can be parsed back into
a RecordTensor with from_existing
or individually into
Records with Record::from_existing
to continue tracking
numerical operations on the data.
§Panics
If the set of dimensions supplied do not match the set of dimensions in this tensor’s shape.
sourcepub fn index(&self) -> TensorAccess<(T, Index), &RecordTensor<'a, T, S, D>, D>
pub fn index(&self) -> TensorAccess<(T, Index), &RecordTensor<'a, T, S, D>, D>
Creates a TensorAccess which will index into the dimensions this record was created with
in the same order as they were provided, both the T
for each record element and
also the index for that record’s entry in the WengertList. These can be parsed back into
a RecordTensor with from_existing
or individually into
Records with Record::from_existing
to continue tracking
numerical operations on the data.
See TensorAccess::from_source_order, get_as_record.
use easy_ml::differentiation::RecordTensor;
use easy_ml::differentiation::WengertList;
use easy_ml::tensors::Tensor;
let list = WengertList::new();
let X = RecordTensor::variables(
&list,
Tensor::from([("a", 3)], vec![ 3.0, 4.0, 5.0 ])
);
let x = X.index().get_as_record([0]);
assert_eq!(x.number, 3.0);
sourcepub fn iter_as_records<'b>(
&'b self
) -> AsRecords<'a, TensorIterator<'b, (T, Index), RecordTensor<'a, T, S, D>, D>, T> ⓘ
pub fn iter_as_records<'b>( &'b self ) -> AsRecords<'a, TensorIterator<'b, (T, Index), RecordTensor<'a, T, S, D>, D>, T> ⓘ
Returns an iterator over this record tensor as Records instead of the raw (T, Index)
data. After manipulating the iterator it can be collected back into a RecordTensor with
RecordTensor::from_iter.
This is a shorthand for AsRecords::from(tensor.history(), TensorIterator::from(&tensor))
source§impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
source§impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
sourcepub fn unary(
&self,
fx: impl Fn(T) -> T,
dfx_dx: impl Fn(T) -> T
) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
pub fn unary( &self, fx: impl Fn(T) -> T, dfx_dx: impl Fn(T) -> T ) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
Creates a new RecordContainer from a reference to an existing RecordContainer by applying
some unary function from T
to T
to every element in the container.
To compute the new records, the unary function of some input x to some output y is needed along with its derivative with respect to its input x.
For example, tanh is a commonly used activation function, but the Real trait does not include this operation and Record has no operations for it specifically. However, you can use this function to compute the tanh for a record container like so:
use easy_ml::differentiation::{RecordTensor, WengertList};
use easy_ml::tensors::Tensor;
let list = WengertList::new();
let X = RecordTensor::variables(
&list,
Tensor::from_fn(
[("rows", 2), ("columns", 2)],
|[r, c]| 0.15 * ((1 + r + c) as f32)
)
);
// the derivative of tanh(x) is sech(x) * sech(x) which is equivalent to
// 1 / (cosh(x) * cosh(x))
let Y = X.unary(|x| x.tanh(), |x| 1.0 / (x.cosh() * x.cosh()));
// we can unwrap here because we know Y contains variables not constants
let derivatives = Y.derivatives().unwrap();
let derivatives_indexing = derivatives.index_by(["rows", "columns"]);
assert_eq!(
derivatives_indexing.get_ref([0, 0]).at_tensor(&X),
Tensor::from(
[("rows", 2), ("columns", 2)],
// [0, 0] element in Y only had the one input variable [0, 0] in X
vec![
0.9778332, 0.0,
0.0, 0.0
]
),
);
assert_eq!(
derivatives_indexing.get_ref([0, 1]).at_tensor(&X),
Tensor::from(
[("rows", 2), ("columns", 2)],
vec![
0.0, 0.915137,
0.0, 0.0
]
),
);
assert_eq!(
// [0, 1] and [1, 0] elements in X had the same starting value so end up with the same
// derivative for their corresponding input variable in X
derivatives_indexing.get_ref([0, 1]).at_tensor(&X).index().get([0, 1]),
derivatives_indexing.get_ref([1, 0]).at_tensor(&X).index().get([1, 0]),
);
assert_eq!(
derivatives_indexing.get_ref([1, 1]).at_tensor(&X),
Tensor::from(
[("rows", 2), ("columns", 2)],
vec![
0.0, 0.0,
0.0, 0.8220013
]
),
);
sourcepub fn binary<S2>(
&self,
rhs: &RecordTensor<'a, T, S2, D>,
fxy: impl Fn(T, T) -> T,
dfxy_dx: impl Fn(T, T) -> T,
dfxy_dy: impl Fn(T, T) -> T
) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
pub fn binary<S2>( &self, rhs: &RecordTensor<'a, T, S2, D>, fxy: impl Fn(T, T) -> T, dfxy_dx: impl Fn(T, T) -> T, dfxy_dy: impl Fn(T, T) -> T ) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
Creates a new RecordContainer from two RecordContainers by applying
some binary function from T
to T
to every element pair in the containers. Both
containers must have the same shape.
To compute the new records, the binary function of some inputs x and y to some output z is needed along with its derivative with respect to its first input x and its derivative with respect to its second input y.
For example, atan2 takes two arguments, but the Real trait does not include this operation and Record has no operations for it specifically. However, you can use this function to compute the atan2 for two record containers like so:
use easy_ml::differentiation::{RecordTensor, WengertList};
use easy_ml::tensors::Tensor;
let list = WengertList::new();
let X = RecordTensor::variables(
&list,
Tensor::from_fn(
[("rows", 2), ("columns", 2)],
|[r, c]| ((1 + r + c) as f32)
)
);
let Y = RecordTensor::variables(
&list,
Tensor::from_fn(
[("rows", 2), ("columns", 2)],
|[r, c]| ((1 + r + c) as f32)
)
);
// the derivative of atan2 with respect to x is y/(x*x + y*y)
// https://www.wolframalpha.com/input/?i=d%28atan2%28x%2Cy%29%29%2Fdx
// the derivative of atan2 with respect to y is -x/(x*x + y*y)
// https://www.wolframalpha.com/input/?i=d%28atan2%28x%2Cy%29%29%2Fdy
let Z = X.binary(&Y,
|x, y| x.atan2(y),
|x, y| y/((x*x) + (y*y)),
|x, y| -x/((x*x) + (y*y))
);
// we can unwrap here because we know Z contains variables not constants
let derivatives = Z.derivatives().unwrap();
// Just as in the unary example, only one pair of the four inputs in X and Y influence the
// outputs in Z, so we have a lot of 0.0 derivatives, and the inputs in [0, 1] and [1, 0]
// are identical so we see the same derivative.
let dZ_dX = derivatives.map(|d| d.at_tensor(&X));
assert_eq!(
dZ_dX,
Tensor::from([("rows", 2), ("columns", 2)], vec![
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.5, 0.0,
0.0, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, 0.25,
0.0, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, 0.0,
0.25, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, 0.0,
0.0, 0.16666667
])
])
);
let dZ_dY = derivatives.map(|d| d.at_tensor(&Y));
assert_eq!(
dZ_dY,
Tensor::from([("rows", 2), ("columns", 2)], vec![
Tensor::from([("rows", 2), ("columns", 2)], vec![
-0.5, 0.0,
0.0, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, -0.25,
0.0, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, 0.0,
-0.25, 0.0
]),
Tensor::from([("rows", 2), ("columns", 2)], vec![
0.0, 0.0,
0.0, -0.16666667
])
])
);
§Panics
- If both record containers have a WengertList that are different to each other
- If the record containers have different shapes
sourcepub fn map(
&self,
fx: impl Fn(Record<'a, T>) -> Record<'a, T>
) -> Result<RecordTensor<'a, T, Tensor<(T, Index), D>, D>, InconsistentHistory<'a, T>>
pub fn map( &self, fx: impl Fn(Record<'a, T>) -> Record<'a, T> ) -> Result<RecordTensor<'a, T, Tensor<(T, Index), D>, D>, InconsistentHistory<'a, T>>
Creates a new RecordContainer from a reference to an existing RecordContainer by applying
some unary function on Record<T>
to Record<T>
to every element in the container. This
will fail if the function would create records with inconsistent histories.
When used with pure functions that can’t return different histories for different inputs unwrapping with always succeed.
This API can allow you to call a generic function that operates on Numeric numbers and apply all the correct derivative tracking during the intermediate calculations for you, without having to resort to storing the Record types.
use easy_ml::numeric::Numeric;
use easy_ml::numeric::extra::Real;
use easy_ml::tensors::Tensor;
use easy_ml::differentiation::{RecordTensor, WengertList};
fn sigmoid<T: Numeric + Real+ Copy>(x: T) -> T {
T::one() / (T::one() + (-x).exp())
}
let history = WengertList::new();
let layer = RecordTensor::variables(&history, Tensor::from([("x", 2)], vec![ 0.2, 0.6 ]));
let after = layer.map(sigmoid).unwrap(); // sigmoid can't introduce inconsistent histories
NB: Mapping a RecordTensor of constants to variables is not inconsistent, the history after mapping doesn’t have to be the same as before, only must be the same for every mapped element.
See also: AsRecords
sourcepub fn map_with_index(
&self,
fx: impl Fn([usize; D], Record<'a, T>) -> Record<'a, T>
) -> Result<RecordTensor<'a, T, Tensor<(T, Index), D>, D>, InconsistentHistory<'a, T>>
pub fn map_with_index( &self, fx: impl Fn([usize; D], Record<'a, T>) -> Record<'a, T> ) -> Result<RecordTensor<'a, T, Tensor<(T, Index), D>, D>, InconsistentHistory<'a, T>>
Creates a new RecordContainer from a reference to an existing RecordContainer by applying
some unary function on Record<T>
and each index of that position in the Record to
Record<T>
to every element in the container. This will fail if the function would create
records with inconsistent histories.
When used with pure functions that can’t return different histories for different inputs unwrapping with always succeed.
This API can allow you to call a generic function that operates on Numeric numbers and apply all the correct derivative tracking during the intermediate calculations for you, without having to resort to storing the Record types.
NB: Mapping a RecordTensor of constants to variables is not inconsistent, the history after mapping doesn’t have to be the same as before, only must be the same for every mapped element.
sourcepub fn derivatives(&self) -> Option<Tensor<Derivatives<T>, D>>
pub fn derivatives(&self) -> Option<Tensor<Derivatives<T>, D>>
For each record in the container, peforms a backward pass up its WengertList from it as the output, computing all the derivatives for the inputs involving this output.
If this container has no backing WengertList, ie was created as constants, then None is returned instead. Otherwise the returned Tensor will have the same shape as this container, with the respective derivatives matching each element in this container.
If you have N inputs x1 to xN, and this output is Y with M outputs, then this computes all the derivatives δyj/δxi for i = 1 to N and j = 1 to M.
If you have a lot of outputs this could be very expensive! Reverse auto diff is optimised for domains where there are many more inputs than outputs.
If you only need some of the derivatives then derivatives_for can be used instead to avoid calculating the rest.
sourcepub fn derivatives_for(&self, indexes: [usize; D]) -> Option<Derivatives<T>>
pub fn derivatives_for(&self, indexes: [usize; D]) -> Option<Derivatives<T>>
For the record at the index, peforms a backward pass up its WengertList from it as the output, computing all the derivatives for the inputs involving this output.
If the index is invalid or this container has no backing WengertList, ie was created as constants, then None is returned instead.
If you have N inputs x1 to xN, and this output is y, then this computes all the derivatives δy/δxi for i = 1 to N.
sourcepub fn elementwise_multiply<S2>(
&self,
other: &RecordTensor<'a, T, S2, D>
) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
pub fn elementwise_multiply<S2>( &self, other: &RecordTensor<'a, T, S2, D> ) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
Performs elementwise multiplication for two record tensors of the same shape.
§Panics
- If both record containers have a WengertList that are different to each other
- If the record containers have different shapes
sourcepub fn elementwise_divide<S2>(
&self,
other: &RecordTensor<'a, T, S2, D>
) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
pub fn elementwise_divide<S2>( &self, other: &RecordTensor<'a, T, S2, D> ) -> RecordTensor<'a, T, Tensor<(T, Index), D>, D>
Performs elementwise division for two record tensors of the same shape.
§Panics
- If both record containers have a WengertList that are different to each other
- If the record containers have different shapes
source§impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
sourcepub fn unary_assign(&mut self, fx: impl Fn(T) -> T, dfx_dx: impl Fn(T) -> T)
pub fn unary_assign(&mut self, fx: impl Fn(T) -> T, dfx_dx: impl Fn(T) -> T)
Overwrites a RecordContainer by applying
some unary function from T
to T
to every element in the container.
To compute the new records, the unary function of some input x to some output y is needed along with its derivative with respect to its input x.
sourcepub fn binary_left_assign<S2>(
&mut self,
rhs: &RecordTensor<'a, T, S2, D>,
fxy: impl Fn(T, T) -> T,
dfxy_dx: impl Fn(T, T) -> T,
dfxy_dy: impl Fn(T, T) -> T
)
pub fn binary_left_assign<S2>( &mut self, rhs: &RecordTensor<'a, T, S2, D>, fxy: impl Fn(T, T) -> T, dfxy_dx: impl Fn(T, T) -> T, dfxy_dy: impl Fn(T, T) -> T )
Overwrites the left hand side of a RecordContainer with the result of applying
some binary function from T
to T
to every element pair in the containers. Both
containers must have the same shape.
To compute the new records, the binary function of some inputs x and y to some
output z is needed along with its derivative with respect to its first input x and
its derivative with respect to its second input y.
§Panics
- If both record containers have a WengertList that are different to each other
- If the record containers have different shapes
sourcepub fn do_unary_assign(
self,
fx: impl Fn(T) -> T,
dfx_dx: impl Fn(T) -> T
) -> Self
pub fn do_unary_assign( self, fx: impl Fn(T) -> T, dfx_dx: impl Fn(T) -> T ) -> Self
A convenience helper function which takes the RecordContainer value and calls unary_assign on it, returning the record container which now contains the result of the operation.
sourcepub fn do_binary_left_assign<S2>(
self,
rhs: &RecordTensor<'a, T, S2, D>,
fxy: impl Fn(T, T) -> T,
dfxy_dx: impl Fn(T, T) -> T,
dfxy_dy: impl Fn(T, T) -> T
) -> Self
pub fn do_binary_left_assign<S2>( self, rhs: &RecordTensor<'a, T, S2, D>, fxy: impl Fn(T, T) -> T, dfxy_dx: impl Fn(T, T) -> T, dfxy_dy: impl Fn(T, T) -> T ) -> Self
A convenience helper function which takes the left hand side by value and calls binary_left_assign on it, returning the left hand side which now contains the result of the operation.
sourcepub fn map_mut(
&mut self,
fx: impl Fn(Record<'a, T>) -> Record<'a, T>
) -> Result<(), InconsistentHistory<'a, T>>
pub fn map_mut( &mut self, fx: impl Fn(Record<'a, T>) -> Record<'a, T> ) -> Result<(), InconsistentHistory<'a, T>>
Updates this RecordContainer in place by applying some unary function on Record<T>
to
Record<T>
to every element in the container. This will fail if the function would create
records with inconsistent histories.
When used with pure functions that can’t return different histories for different inputs unwrapping with always succeed.
Since this updates the container in place, if Err is returned then the data in this RecordContainer is still available but it has been corrupted - at least one of the elements should have a different history than what it will have because the mapping function created inconsistent histories that couldn’t be represented by the container as it only stores one.
This API can allow you to call a generic function that operates on Numeric numbers and apply all the correct derivative tracking during the intermediate calculations for you, without having to resort to storing the Record types.
NB: Mapping a RecordTensor of constants to variables is not inconsistent, the history after mapping doesn’t have to be the same as before, only must be the same for every mapped element.
You might also use this function at the end of a training loop to update all the weights to reduce their loss.
use easy_ml::numeric::Numeric;
use easy_ml::tensors::Tensor;
use easy_ml::differentiation::{Record, RecordTensor, WengertList};
let history = WengertList::new();
let mut weights = RecordTensor::variables(
&history,
Tensor::from([("w1", 4)], vec![ 0.3, 0.2, -1.2, -0.4 ])
);
let error = {
// this is over-simplified for brevity, obviously in a real scenario we wouldn't have a
// function that calculates the error like this or we wouldn't be doing machine learning
// to fit it in the first place
let mut loss = Record::variable(0.0, &history);
for r in weights.iter_as_records() {
loss = loss + r;
}
loss
};
let derivatives = error.derivatives();
let learning_rate = 0.1;
// update the weights to contain less error than they did before
let result = weights.map_mut(|x| x - (derivatives[&x] * learning_rate));
assert!(result.is_ok()); // we know we didn't introduce an inconsistent history just updating the weights
sourcepub fn map_mut_with_index(
&mut self,
fx: impl Fn([usize; D], Record<'a, T>) -> Record<'a, T>
) -> Result<(), InconsistentHistory<'a, T>>
pub fn map_mut_with_index( &mut self, fx: impl Fn([usize; D], Record<'a, T>) -> Record<'a, T> ) -> Result<(), InconsistentHistory<'a, T>>
Updates this RecordContainer in place by applying some unary function on Record<T>
and
each index of that position in the Record to Record<T>
to every element in the container.
This will fail if the function would create records with inconsistent histories.
When used with pure functions that can’t return different histories for different inputs unwrapping with always succeed.
Since this updates the container in place, if Err is returned then the data in this RecordContainer is still available but it has been corrupted - at least one of the elements should have a different history than what it will have because the mapping function created inconsistent histories that couldn’t be represented by the container as it only stores one.
This API can allow you to call a generic function that operates on Numeric numbers and apply all the correct derivative tracking during the intermediate calculations for you, without having to resort to storing the Record types.
NB: Mapping a RecordTensor of constants to variables is not inconsistent, the history after mapping doesn’t have to be the same as before, only must be the same for every mapped element.
source§impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> RecordTensor<'a, T, S, D>
sourcepub fn binary_right_assign<S2>(
&self,
rhs: &mut RecordTensor<'a, T, S2, D>,
fxy: impl Fn(T, T) -> T,
dfxy_dx: impl Fn(T, T) -> T,
dfxy_dy: impl Fn(T, T) -> T
)
pub fn binary_right_assign<S2>( &self, rhs: &mut RecordTensor<'a, T, S2, D>, fxy: impl Fn(T, T) -> T, dfxy_dx: impl Fn(T, T) -> T, dfxy_dy: impl Fn(T, T) -> T )
Overwrites the right hand side of a RecordContainer with the result of applying
some binary function from T
to T
to every element pair in the containers. Both
containers must have the same shape.
To compute the new records, the binary function of some inputs x and y to some
output z is needed along with its derivative with respect to its first input x and
its derivative with respect to its second input y.
§Panics
- If both record containers have a WengertList that are different to each other
- If the record containers have different shapes
sourcepub fn do_binary_right_assign<S2>(
&self,
rhs: RecordTensor<'a, T, S2, D>,
fxy: impl Fn(T, T) -> T,
dfxy_dx: impl Fn(T, T) -> T,
dfxy_dy: impl Fn(T, T) -> T
) -> RecordTensor<'a, T, S2, D>
pub fn do_binary_right_assign<S2>( &self, rhs: RecordTensor<'a, T, S2, D>, fxy: impl Fn(T, T) -> T, dfxy_dx: impl Fn(T, T) -> T, dfxy_dy: impl Fn(T, T) -> T ) -> RecordTensor<'a, T, S2, D>
A convenience helper function which takes the right hand side by value and calls binary_right_assign on it, returning the right hand side which now contains the result of the operation.
Trait Implementations§
source§impl<'a, T, S1, S2, const D: usize> Add<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Add<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
Operation for two record tensors with both referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
+
operator.source§impl<'a, T, S1, S2, const D: usize> Add<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Add<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
Operation for two record tensors with the right referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
+
operator.source§impl<'a, T, S1, const D: usize> Add<&T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Add<&T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with both referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Add<&T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Add<&T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the right referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, S2, const D: usize> Add<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Add<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
Operation for two record tensors with the left referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
+
operator.source§impl<'a, T, S1, S2, const D: usize> Add<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Add<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
Operation for two record tensors of the same type.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
+
operator.source§impl<'a, T, S1, const D: usize> Add<T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Add<T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the left referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Add<T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Add<T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Cos for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Cos for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Cos for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Cos for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T, S, const D: usize> Display for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Display for RecordTensor<'a, T, S, D>
A record tensor is displayed by showing its number components.
source§impl<'a, T, S1, const D: usize> Div<&T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Div<&T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with both referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Div<&T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Div<&T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the right referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Div<T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Div<T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the left referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Div<T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Div<T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Exp for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Exp for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Exp for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Exp for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T> From<&Record<'a, T>> for RecordTensor<'a, T, Tensor<(T, Index), 0>, 0>
impl<'a, T> From<&Record<'a, T>> for RecordTensor<'a, T, Tensor<(T, Index), 0>, 0>
A record can be converted losslessly into a zero dimensional record tensor.
source§impl<'a, T> From<Record<'a, T>> for RecordTensor<'a, T, Tensor<(T, Index), 0>, 0>
impl<'a, T> From<Record<'a, T>> for RecordTensor<'a, T, Tensor<(T, Index), 0>, 0>
A record can be converted losslessly into a zero dimensional record tensor.
source§impl<'a, T, S, const D: usize> Ln for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Ln for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Ln for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Ln for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T, S1, S2> Mul<&RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for &RecordTensor<'a, T, S1, 2>
impl<'a, T, S1, S2> Mul<&RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for &RecordTensor<'a, T, S1, 2>
Matrix multiplication for two record tensors with both referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
*
operator.source§impl<'a, T, S1, S2> Mul<&RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for RecordTensor<'a, T, S1, 2>
impl<'a, T, S1, S2> Mul<&RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for RecordTensor<'a, T, S1, 2>
Matrix multiplication for two record tensors with the right referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
*
operator.source§impl<'a, T, S1, const D: usize> Mul<&T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Mul<&T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with both referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Mul<&T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Mul<&T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the right referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, S2> Mul<RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for &RecordTensor<'a, T, S1, 2>
impl<'a, T, S1, S2> Mul<RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for &RecordTensor<'a, T, S1, 2>
Matrix multiplication for two record tensors with the left referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
*
operator.source§impl<'a, T, S1, S2> Mul<RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for RecordTensor<'a, T, S1, 2>
impl<'a, T, S1, S2> Mul<RecordContainer<'a, T, TensorView<(T, usize), S2, 2>, 2>> for RecordTensor<'a, T, S1, 2>
Matrix multiplication for two record tensors of the same type.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), 2>, 2>, 2>
*
operator.source§impl<'a, T, S1, const D: usize> Mul<T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Mul<T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the left referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Mul<T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Mul<T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Neg for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Neg for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Neg for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Neg for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T, S, const D: usize> Pow<&T> for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Pow<&T> for &RecordTensor<'a, T, S, D>
Operation for a record tensor and a constant with both referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Pow<&T> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Pow<&T> for RecordTensor<'a, T, S, D>
Operation for a record tensor and a referenced constant. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Pow<T> for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Pow<T> for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Pow<T> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Pow<T> for RecordTensor<'a, T, S, D>
Operation for a record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> Sin for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Sin for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Sin for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Sin for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T, S, const D: usize> Sqrt for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Sqrt for &RecordTensor<'a, T, S, D>
Operation for a referenced record tensor of some type.
source§impl<'a, T, S, const D: usize> Sqrt for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> Sqrt for RecordTensor<'a, T, S, D>
Operation for a record tensor of some type.
source§impl<'a, T, S1, S2, const D: usize> Sub<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Sub<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
Operation for two record tensors with both referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
-
operator.source§impl<'a, T, S1, S2, const D: usize> Sub<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Sub<&RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
Operation for two record tensors with the right referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
-
operator.source§impl<'a, T, S1, const D: usize> Sub<&T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Sub<&T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with both referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Sub<&T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Sub<&T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the right referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, S2, const D: usize> Sub<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Sub<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for &RecordTensor<'a, T, S1, D>
Operation for two record tensors with the left referenced.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
-
operator.source§impl<'a, T, S1, S2, const D: usize> Sub<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, S2, const D: usize> Sub<RecordContainer<'a, T, TensorView<(T, usize), S2, D>, D>> for RecordTensor<'a, T, S1, D>
Operation for two record tensors of the same type.
§type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
-
operator.source§impl<'a, T, S1, const D: usize> Sub<T> for &RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Sub<T> for &RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant with the left referenced. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S1, const D: usize> Sub<T> for RecordTensor<'a, T, S1, D>
impl<'a, T, S1, const D: usize> Sub<T> for RecordTensor<'a, T, S1, D>
Operation for a record tensor and a constant of the same type. The scalar is applied to all elements, this is a shorthand for unary().
source§impl<'a, T, S, const D: usize> SwappedOperations<&T> for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> SwappedOperations<&T> for &RecordTensor<'a, T, S, D>
source§fn sub_swapped(self, lhs: &T) -> Self::Output
fn sub_swapped(self, lhs: &T) -> Self::Output
Subtraction for a record tensor and a constant, where the constant is the left hand side, ie C - record.
source§fn div_swapped(self, lhs: &T) -> Self::Output
fn div_swapped(self, lhs: &T) -> Self::Output
Division for a record tensor and a constant, where the constant is the left hand side, ie C / record.
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
source§impl<'a, T, S, const D: usize> SwappedOperations<&T> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> SwappedOperations<&T> for RecordTensor<'a, T, S, D>
source§fn sub_swapped(self, lhs: &T) -> Self::Output
fn sub_swapped(self, lhs: &T) -> Self::Output
Subtraction for a record tensor and a constant, where the constant is the left hand side, ie C - record.
source§fn div_swapped(self, lhs: &T) -> Self::Output
fn div_swapped(self, lhs: &T) -> Self::Output
Division for a record tensor and a constant, where the constant is the left hand side, ie C / record.
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
source§impl<'a, T, S, const D: usize> SwappedOperations<T> for &RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> SwappedOperations<T> for &RecordTensor<'a, T, S, D>
source§fn sub_swapped(self, lhs: T) -> Self::Output
fn sub_swapped(self, lhs: T) -> Self::Output
Subtraction for a record tensor and a constant, where the constant is the left hand side, ie C - record.
source§fn div_swapped(self, lhs: T) -> Self::Output
fn div_swapped(self, lhs: T) -> Self::Output
Division for a record tensor and a constant, where the constant is the left hand side, ie C / record.
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
source§impl<'a, T, S, const D: usize> SwappedOperations<T> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> SwappedOperations<T> for RecordTensor<'a, T, S, D>
source§fn sub_swapped(self, lhs: T) -> Self::Output
fn sub_swapped(self, lhs: T) -> Self::Output
Subtraction for a record tensor and a constant, where the constant is the left hand side, ie C - record.
source§fn div_swapped(self, lhs: T) -> Self::Output
fn div_swapped(self, lhs: T) -> Self::Output
Division for a record tensor and a constant, where the constant is the left hand side, ie C / record.
type Output = RecordContainer<'a, T, TensorView<(T, usize), Tensor<(T, usize), D>, D>, D>
source§impl<'a, T, S, const D: usize> TensorMut<(T, usize), D> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> TensorMut<(T, usize), D> for RecordTensor<'a, T, S, D>
RecordTensor implements TensorMut when the source does, returning mutable references to the
tuples of T
and Index
.
source§fn get_reference_mut(&mut self, indexes: [usize; D]) -> Option<&mut (T, Index)>
fn get_reference_mut(&mut self, indexes: [usize; D]) -> Option<&mut (T, Index)>
source§unsafe fn get_reference_unchecked_mut(
&mut self,
indexes: [usize; D]
) -> &mut (T, Index)
unsafe fn get_reference_unchecked_mut( &mut self, indexes: [usize; D] ) -> &mut (T, Index)
source§impl<'a, T, S, const D: usize> TensorRef<(T, usize), D> for RecordTensor<'a, T, S, D>
impl<'a, T, S, const D: usize> TensorRef<(T, usize), D> for RecordTensor<'a, T, S, D>
RecordTensor implements TensorRef when the source does, returning references to the tuples
of T
and Index
.