11// Element-wise methods for ndarray
22
3- #[ cfg( feature = "std" ) ]
4- use num_complex:: Complex ;
3+ use num_complex:: { Complex32 , Complex64 } ;
54#[ cfg( feature = "std" ) ]
65use num_traits:: Float ;
76
87use crate :: imp_prelude:: * ;
98
109/// Trait for types that can generalize the phase angle (argument)
1110/// calculation for both real floats and complex numbers.
12- #[ cfg( feature = "std" ) ]
13- pub trait HasAngle < F : Float >
11+ pub trait HasAngle
1412{
13+ /// The type of the associated angle.
14+ type Angle ;
15+
1516 /// Return the phase angle (argument) of the value
16- fn to_angle ( & self ) -> F ;
17+ fn to_angle ( & self ) -> Self :: Angle ;
1718}
1819
19- #[ cfg( feature = "std" ) ]
20- impl < F > HasAngle < F > for F
21- where F : Float
20+ impl HasAngle for f32
2221{
22+ type Angle = Self ;
23+
2324 #[ inline]
24- fn to_angle ( & self ) -> F
25+ fn to_angle ( & self ) -> Self
2526 {
26- F :: zero ( ) . atan2 ( * self )
27+ 0f32 . atan2 ( * self )
2728 }
2829}
2930
30- #[ cfg( feature = "std" ) ]
31- impl < F > HasAngle < F > for Complex < F >
32- where F : Float
31+ impl HasAngle for f64
32+ {
33+ type Angle = Self ;
34+
35+ #[ inline]
36+ fn to_angle ( & self ) -> Self
37+ {
38+ 0f64 . atan2 ( * self )
39+ }
40+ }
41+
42+ impl HasAngle for Complex32
43+ {
44+ type Angle = f32 ;
45+
46+ #[ inline]
47+ fn to_angle ( & self ) -> Self :: Angle
48+ {
49+ self . im . atan2 ( self . re )
50+ }
51+ }
52+
53+ impl HasAngle for Complex64
3354{
55+ type Angle = f64 ;
56+
3457 #[ inline]
35- fn to_angle ( & self ) -> F
58+ fn to_angle ( & self ) -> Self :: Angle
3659 {
3760 self . im . atan2 ( self . re )
3861 }
@@ -203,10 +226,10 @@ where
203226/// # Angle calculation methods for arrays
204227///
205228/// Methods for calculating phase angles of complex values in arrays.
206- #[ cfg( feature = "std" ) ]
207- #[ cfg_attr( docsrs, doc( cfg( feature = "std" ) ) ) ]
208229impl < A , D > ArrayRef < A , D >
209- where D : Dimension
230+ where
231+ D : Dimension ,
232+ A : HasAngle ,
210233{
211234 /// Return the [phase angle (argument)](https://en.wikipedia.org/wiki/Argument_(complex_analysis)) of complex values in the array.
212235 ///
@@ -241,10 +264,9 @@ where D: Dimension
241264 /// assert!((angles[2] - PI/4.0).abs() < 1e-10);
242265 /// ```
243266 #[ must_use = "method returns a new array and does not mutate the original value" ]
244- pub fn angle < F : Float > ( & self ) -> Array < F , D >
245- where A : HasAngle < F > + Clone
267+ pub fn angle ( & self ) -> Array < A :: Angle , D >
246268 {
247- self . mapv ( |f| A :: to_angle ( & f ) )
269+ self . map ( A :: to_angle)
248270 }
249271}
250272
@@ -273,77 +295,9 @@ where
273295 }
274296}
275297
276- /// Scalar convenience function for angle calculation.
277- ///
278- /// Calculate the [phase angle (argument)](https://en.wikipedia.org/wiki/Argument_(complex_analysis)) of a single complex value.
279- ///
280- /// # Arguments
281- ///
282- /// * `z` - A real or complex value (f32/f64, `Complex<f32>`/`Complex<f64>`).
283- ///
284- /// # Returns
285- ///
286- /// The phase angle as `f64` in radians or degrees.
287- ///
288- /// # Examples
289- ///
290- /// ```
291- /// use num_complex::Complex;
292- /// use std::f64::consts::PI;
293- ///
294- /// assert!((ndarray::angle_scalar(Complex::new(1.0f64, 1.0)) - PI/4.0).abs() < 1e-10);
295- /// assert!((ndarray::angle_scalar(1.0f32) - 0.0).abs() < 1e-10);
296- /// assert!((ndarray::angle_scalar(-1.0f32) - 180.0).abs() < 1e-10);
297- /// ```
298- #[ cfg( feature = "std" ) ]
299- #[ cfg_attr( docsrs, doc( cfg( feature = "std" ) ) ) ]
300- pub fn angle_scalar < F : Float , T : HasAngle < F > > ( z : T ) -> F
301- {
302- z. to_angle ( )
303- }
304-
305- /// Calculate the phase angle of complex values.
306- ///
307- /// # Arguments
308- ///
309- /// * `z` - Array of real or complex values.
310- ///
311- /// # Returns
312- ///
313- /// An `Array<F, D>` with the same shape as `z`.
314- ///
315- /// # Examples
316- ///
317- /// ```
318- /// use ndarray::array;
319- /// use num_complex::Complex;
320- ///
321- /// // f32 precision for complex numbers
322- /// let z32 = array![Complex::new(0.0f32, 1.0)];
323- /// let out32 = ndarray::angle(&z32);
324- /// // out32 has type Array<f32, _>
325- ///
326- /// // f64 precision for complex numbers
327- /// let z64 = array![Complex::new(0.0f64, -1.0)];
328- /// let out64 = ndarray::angle(&z64);
329- /// // out64 has type Array<f64, _>
330- /// ```
331- #[ cfg( feature = "std" ) ]
332- #[ cfg_attr( docsrs, doc( cfg( feature = "std" ) ) ) ]
333- pub fn angle < A , F , S , D > ( z : & ArrayBase < S , D > ) -> Array < F , D >
334- where
335- A : HasAngle < F > ,
336- F : Float ,
337- S : Data < Elem = A > ,
338- D : Dimension ,
339- {
340- z. map ( HasAngle :: to_angle)
341- }
342-
343298#[ cfg( all( test, feature = "std" ) ) ]
344299mod angle_tests
345300{
346- use super :: * ;
347301 use crate :: Array ;
348302 use num_complex:: Complex ;
349303 use std:: f64:: consts:: PI ;
@@ -392,7 +346,7 @@ mod angle_tests
392346 fn test_complex_numbers_radians ( )
393347 {
394348 let arr = Array :: from_vec ( vec ! [
395- Complex :: new( 1.0 , 0.0 ) , // 0
349+ Complex :: new( 1.0f64 , 0.0 ) , // 0
396350 Complex :: new( 0.0 , 1.0 ) , // π/2
397351 Complex :: new( -1.0 , 0.0 ) , // π
398352 Complex :: new( 0.0 , -1.0 ) , // -π/2
@@ -413,7 +367,7 @@ mod angle_tests
413367 fn test_complex_numbers_degrees ( )
414368 {
415369 let arr = Array :: from_vec ( vec ! [
416- Complex :: new( 1.0 , 0.0 ) ,
370+ Complex :: new( 1.0f64 , 0.0 ) ,
417371 Complex :: new( 0.0 , 1.0 ) ,
418372 Complex :: new( -1.0 , 0.0 ) ,
419373 Complex :: new( 1.0 , 1.0 ) ,
@@ -430,7 +384,7 @@ mod angle_tests
430384 fn test_signed_zeros ( )
431385 {
432386 let arr = Array :: from_vec ( vec ! [
433- Complex :: new( 0.0 , 0.0 ) ,
387+ Complex :: new( 0.0f64 , 0.0 ) ,
434388 Complex :: new( -0.0 , 0.0 ) ,
435389 Complex :: new( 0.0 , -0.0 ) ,
436390 Complex :: new( -0.0 , -0.0 ) ,
@@ -443,51 +397,6 @@ mod angle_tests
443397 assert_approx_eq ! ( a[ 3 ] , -PI , 1e-10 ) ;
444398 }
445399
446- #[ test]
447- fn test_angle_scalar_f64 ( )
448- {
449- assert_approx_eq ! ( angle_scalar( Complex :: new( 1.0 , 1.0 ) ) , PI / 4.0 , 1e-10 ) ;
450- assert_approx_eq ! ( angle_scalar( 1.0f64 ) , 0.0 , 1e-10 ) ;
451- assert_approx_eq ! ( angle_scalar( -1.0f64 ) , PI , 1e-10 ) ;
452- }
453-
454- #[ test]
455- fn test_angle_scalar_f32 ( )
456- {
457- use std:: f32:: consts:: FRAC_PI_4 ;
458- assert_approx_eq ! ( angle_scalar( Complex :: new( 1.0f32 , 1.0 ) ) , FRAC_PI_4 , 1e-6 ) ;
459- assert_approx_eq ! ( angle_scalar( 1.0f32 ) , 0.0 , 1e-6 ) ;
460- assert_approx_eq ! ( angle_scalar( -1.0f32 ) , std:: f32 :: consts:: PI , 1e-6 ) ;
461- }
462-
463- #[ test]
464- fn test_angle_function ( )
465- {
466- let arr = Array :: from_vec ( vec ! [
467- Complex :: new( 1.0 , 0.0 ) ,
468- Complex :: new( 0.0 , 1.0 ) ,
469- Complex :: new( -1.0 , 1.0 ) ,
470- ] ) ;
471- let a = angle ( & arr) ;
472-
473- assert_approx_eq ! ( a[ 0 ] , 0.0 , 1e-10 ) ;
474- assert_approx_eq ! ( a[ 1 ] , PI / 2.0 , 1e-10 ) ;
475- assert_approx_eq ! ( a[ 2 ] , 3.0 * PI / 4.0 , 1e-10 ) ;
476- }
477-
478- #[ test]
479- fn test_angle_function_degrees ( )
480- {
481- let arr = Array :: from_vec ( vec ! [
482- Complex :: new( 1.0f32 , 1.0 ) ,
483- Complex :: new( -1.0f32 , 0.0 ) ,
484- ] ) ;
485- let a = angle ( & arr) ;
486-
487- assert_approx_eq ! ( a[ 0 ] , 45.0f32 . to_radians( ) , 1e-6 ) ;
488- assert_approx_eq ! ( a[ 1 ] , 180.0f32 . to_radians( ) , 1e-6 ) ;
489- }
490-
491400 #[ test]
492401 fn test_edge_cases ( )
493402 {
0 commit comments