Skip to content

Implement arithmetic ops on more combinations of types #744

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Generalize arithmetic op impls
  • Loading branch information
jturner314 committed Oct 18, 2019
commit e1e825b58d5e8bb0ecbae13bd165ff426af6957f
180 changes: 39 additions & 141 deletions src/impl_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ macro_rules! impl_binary_op(
/// Perform elementwise
#[doc=$doc]
/// between `self` and `rhs`,
/// and return the result (based on `self`).
///
/// `self` must be an `Array` or `ArcArray`.
/// and return the result.
///
/// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
Expand All @@ -64,13 +62,13 @@ impl<A, B, S, S2, D, E> $trt<ArrayBase<S2, E>> for ArrayBase<S, D>
where
A: Clone + $trt<B, Output=A>,
B: Clone,
S: DataOwned<Elem=A> + DataMut,
S: Data<Elem=A>,
S2: Data<Elem=B>,
D: Dimension,
E: Dimension,
{
type Output = ArrayBase<S, D>;
fn $mth(self, rhs: ArrayBase<S2, E>) -> ArrayBase<S, D>
type Output = Array<A, D>;
fn $mth(self, rhs: ArrayBase<S2, E>) -> Array<A, D>
{
self.$mth(&rhs)
}
Expand All @@ -79,7 +77,7 @@ where
/// Perform elementwise
#[doc=$doc]
/// between `self` and reference `rhs`,
/// and return the result (based on `self`).
/// and return the result.
///
/// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
Expand All @@ -88,18 +86,19 @@ impl<'a, A, B, S, S2, D, E> $trt<&'a ArrayBase<S2, E>> for ArrayBase<S, D>
where
A: Clone + $trt<B, Output=A>,
B: Clone,
S: DataOwned<Elem=A> + DataMut,
S: Data<Elem=A>,
S2: Data<Elem=B>,
D: Dimension,
E: Dimension,
{
type Output = ArrayBase<S, D>;
fn $mth(mut self, rhs: &ArrayBase<S2, E>) -> ArrayBase<S, D>
type Output = Array<A, D>;
fn $mth(self, rhs: &ArrayBase<S2, E>) -> Array<A, D>
{
self.zip_mut_with(rhs, |x, y| {
let mut lhs = self.into_owned();
lhs.zip_mut_with(rhs, |x, y| {
*x = x.clone() $operator y.clone();
});
self
lhs
}
}

Expand Down Expand Up @@ -129,67 +128,23 @@ where

/// Perform elementwise
#[doc=$doc]
/// between references `self` and `rhs`,
/// and return the result as a new `Array`.
///
/// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
/// **Panics** if broadcasting isn’t possible.
impl<'a, 'b, A, B, S2, D, E> $trt<&'b ArrayBase<S2, E>> for ArrayView<'a, A, D>
where
A: Clone + $trt<B, Output=A>,
B: Clone,
S2: Data<Elem=B>,
D: Dimension,
E: Dimension,
{
type Output = Array<A, D>;
fn $mth(self, rhs: &'b ArrayBase<S2, E>) -> Array<A, D> {
// FIXME: Can we co-broadcast arrays here? And how?
self.to_owned().$mth(rhs)
}
}

/// Perform elementwise
#[doc=$doc]
/// between references `self` and `rhs`,
/// between `self` and `rhs`,
/// and return the result as a new `Array`.
///
/// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
/// **Panics** if broadcasting isn’t possible.
impl<'a, 'b, A, B, S, D, E> $trt<ArrayView<'b, B, E>> for &'a ArrayBase<S, D>
impl<'a, A, B, S, S2, D, E> $trt<ArrayBase<S2, E>> for &'a ArrayBase<S, D>
where
A: Clone + $trt<B, Output=A>,
B: Clone,
S: Data<Elem=A>,
S2: Data<Elem=B>,
D: Dimension,
E: Dimension,
{
type Output = Array<A, D>;
fn $mth(self, rhs: ArrayView<'b, B, E>) -> Array<A, D> {
// FIXME: Can we co-broadcast arrays here? And how?
self.to_owned().$mth(rhs)
}
}

/// Perform elementwise
#[doc=$doc]
/// between references `self` and `rhs`,
/// and return the result as a new `Array`.
///
/// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
/// **Panics** if broadcasting isn’t possible.
impl<'a, 'b, A, B, D, E> $trt<ArrayView<'b, B, E>> for ArrayView<'a, A, D>
where
A: Clone + $trt<B, Output=A>,
B: Clone,
D: Dimension,
E: Dimension,
{
type Output = Array<A, D>;
fn $mth(self, rhs: ArrayView<'b, B, E>) -> Array<A, D> {
fn $mth(self, rhs: ArrayBase<S2, E>) -> Array<A, D> {
// FIXME: Can we co-broadcast arrays here? And how?
self.to_owned().$mth(rhs)
}
Expand All @@ -198,21 +153,20 @@ where
/// Perform elementwise
#[doc=$doc]
/// between `self` and the scalar `x`,
/// and return the result (based on `self`).
///
/// `self` must be an `Array` or `ArcArray`.
/// and return the result.
impl<A, S, D, B> $trt<B> for ArrayBase<S, D>
where A: Clone + $trt<B, Output=A>,
S: DataOwned<Elem=A> + DataMut,
S: Data<Elem=A>,
D: Dimension,
B: ScalarOperand,
{
type Output = ArrayBase<S, D>;
fn $mth(mut self, x: B) -> ArrayBase<S, D> {
self.unordered_foreach_mut(move |elt| {
type Output = Array<A, D>;
fn $mth(self, x: B) -> Array<A, D> {
let mut lhs = self.into_owned();
lhs.unordered_foreach_mut(move |elt| {
*elt = elt.clone() $operator x.clone();
});
self
lhs
}
}

Expand All @@ -231,21 +185,6 @@ impl<'a, A, S, D, B> $trt<B> for &'a ArrayBase<S, D>
self.to_owned().$mth(x)
}
}

/// Perform elementwise
#[doc=$doc]
/// between the reference `self` and the scalar `x`,
/// and return the result as a new `Array`.
impl<'a, A, D, B> $trt<B> for ArrayView<'a, A, D>
where A: Clone + $trt<B, Output=A>,
D: Dimension,
B: ScalarOperand,
{
type Output = Array<A, D>;
fn $mth(self, x: B) -> Array<A, D> {
self.to_owned().$mth(x)
}
}
);
);

Expand All @@ -266,17 +205,17 @@ macro_rules! impl_scalar_lhs_op {
// these have no doc -- they are not visible in rustdoc
// Perform elementwise
// between the scalar `self` and array `rhs`,
// and return the result (based on `self`).
// and return the result.
impl<S, D> $trt<ArrayBase<S, D>> for $scalar
where S: DataOwned<Elem=$scalar> + DataMut,
where S: Data<Elem=$scalar>,
D: Dimension,
{
type Output = ArrayBase<S, D>;
fn $mth(self, rhs: ArrayBase<S, D>) -> ArrayBase<S, D> {
type Output = Array<$scalar, D>;
fn $mth(self, rhs: ArrayBase<S, D>) -> Array<$scalar, D> {
if_commutative!($commutative {
rhs.$mth(self)
} or {{
let mut rhs = rhs;
let mut rhs = rhs.into_owned();
rhs.unordered_foreach_mut(move |elt| {
*elt = self $operator *elt;
});
Expand All @@ -301,23 +240,6 @@ impl<'a, S, D> $trt<&'a ArrayBase<S, D>> for $scalar
})
}
}

/// Perform elementwise
/// between the scalar `self` and array `rhs`,
/// and return the result as a new `Array`.
impl<'a, D> $trt<ArrayView<'a, $scalar, D>> for $scalar
where
D: Dimension,
{
type Output = Array<$scalar, D>;
fn $mth(self, rhs: ArrayView<'a, $scalar, D>) -> Array<$scalar, D> {
if_commutative!($commutative {
rhs.$mth(self)
} or {
self.$mth(rhs.to_owned())
})
}
}
);
}

Expand Down Expand Up @@ -393,16 +315,17 @@ mod arithmetic_ops {
impl<A, S, D> Neg for ArrayBase<S, D>
where
A: Clone + Neg<Output = A>,
S: DataOwned<Elem = A> + DataMut,
S: Data<Elem = A>,
D: Dimension,
{
type Output = Self;
type Output = Array<A, D>;
/// Perform an elementwise negation of `self` and return the result.
fn neg(mut self) -> Self {
self.unordered_foreach_mut(|elt| {
fn neg(self) -> Array<A, D> {
let mut array = self.into_owned();
array.unordered_foreach_mut(|elt| {
*elt = -elt.clone();
});
self
array
}
}

Expand All @@ -420,32 +343,20 @@ mod arithmetic_ops {
}
}

impl<'a, A, D> Neg for ArrayView<'a, A, D>
where
for<'b> &'b A: Neg<Output = A>,
D: Dimension,
{
type Output = Array<A, D>;
/// Perform an elementwise negation of reference `self` and return the
/// result as a new `Array`.
fn neg(self) -> Array<A, D> {
self.map(Neg::neg)
}
}

impl<A, S, D> Not for ArrayBase<S, D>
where
A: Clone + Not<Output = A>,
S: DataOwned<Elem = A> + DataMut,
S: Data<Elem = A>,
D: Dimension,
{
type Output = Self;
type Output = Array<A, D>;
/// Perform an elementwise unary not of `self` and return the result.
fn not(mut self) -> Self {
self.unordered_foreach_mut(|elt| {
fn not(self) -> Array<A, D> {
let mut array = self.into_owned();
array.unordered_foreach_mut(|elt| {
*elt = !elt.clone();
});
self
array
}
}

Expand All @@ -462,19 +373,6 @@ mod arithmetic_ops {
self.map(Not::not)
}
}

impl<'a, A, D> Not for ArrayView<'a, A, D>
where
for<'b> &'b A: Not<Output = A>,
D: Dimension,
{
type Output = Array<A, D>;
/// Perform an elementwise unary not of reference `self` and return the
/// result as a new `Array`.
fn not(self) -> Array<A, D> {
self.map(Not::not)
}
}
}

mod assign_ops {
Expand Down
32 changes: 13 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,17 +607,13 @@ pub type Ixs = isize;
///
/// ### Binary Operators with Two Arrays
///
/// Let `A` be an array or view of any kind. Let `O` be an array
/// with owned storage (either `Array` or `ArcArray`).
/// Let `M` be an array with mutable data (either `Array`, `ArcArray`
/// or `ArrayViewMut`). Let `V` be an `ArrayView`.
/// The following combinations of operands
/// are supported for an arbitrary binary operator denoted by `@` (it can be
/// `+`, `-`, `*`, `/` and so on).
///
/// - `&A @ &A`, `&A @ V`, `V @ &A`, or `V @ V` which produce a new `Array`
/// - `O @ A` which consumes `O`, updates it with the result, and returns it
/// - `O @ &A` which consumes `O`, updates it with the result, and returns it
/// Let `A` be an array or view of any kind. Let `M` be an array with mutable
/// data (either `Array`, `ArcArray` or `ArrayViewMut`). The following
/// combinations of operands are supported for an arbitrary binary operator
/// denoted by `@` (it can be `+`, `-`, `*`, `/` and so on).
///
/// - `&A @ &A` or `&A @ A` which produce a new `Array`
/// - `A @ &A` or `A @ A` which may reuse the allocation of the LHS if it's an owned array
/// - `M @= &A` or `M @= A` which performs an arithmetic operation in place on `M`
///
/// Note that the element type needs to implement the operator trait and the
Expand Down Expand Up @@ -646,19 +642,17 @@ pub type Ixs = isize;
/// are supported (scalar can be on either the left or right side, but
/// `ScalarOperand` docs has the detailed condtions).
///
/// - `&A @ K`, `V @ K`, `K @ &A`, or `K @ V` which produces a new `Array`
/// - `O @ K` or `K @ O` which consumes `O`, updates it with the result and returns it
/// - `&A @ K` or `K @ &A` which produces a new `Array`
/// - `A @ K` or `K @ A` which may reuse the allocation of the array if it's an owned array
/// - `M @= K` which performs an arithmetic operation in place
///
/// ### Unary Operators
///
/// Let `A` be an array or view of any kind. Let `O` be an array with owned
/// storage (either `Array` or `ArcArray`). Let `V` be an `ArrayView`. The
/// following operands are supported for an arbitrary unary operator denoted by
/// `@` (it can be `-` or `!`).
/// The following operands are supported for an arbitrary unary operator
/// denoted by `@` (it can be `-` or `!`).
///
/// - `@&A` or `@V` which produces a new `Array`
/// - `@O` which consumes `O`, updates it with the result, and returns it
/// - `@&A` which produces a new `Array`
/// - `@A` which may reuse the allocation of the array if it's an owned array
///
/// ## Broadcasting
///
Expand Down
10 changes: 5 additions & 5 deletions tests/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,11 @@ fn test_add() {
}

let B = A.clone();
A = A + &B;
assert_eq!(A[[0, 0]], 0);
assert_eq!(A[[0, 1]], 2);
assert_eq!(A[[1, 0]], 4);
assert_eq!(A[[1, 1]], 6);
let C = A + &B;
assert_eq!(C[[0, 0]], 0);
assert_eq!(C[[0, 1]], 2);
assert_eq!(C[[1, 0]], 4);
assert_eq!(C[[1, 1]], 6);
}

#[test]
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy