@@ -55,9 +55,111 @@ public static bool any(NDArray a)
5555 /// <param name="axis">Axis or axes along which a logical OR reduction is performed. The default (axis = None) is to perform a logical OR over all the dimensions of the input array. axis may be negative, in which case it counts from the last to the first axis.</param>
5656 /// <returns>A new boolean or ndarray is returned unless out is specified, in which case a reference to out is returned.</returns>
5757 /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.any.html</remarks>
58- public static NDArray < bool > any ( NDArray nd , int axis )
58+ public static NDArray < bool > any ( NDArray nd , int axis , bool keepdims )
5959 {
60- throw new NotImplementedException ( ) ; //TODO
60+ if ( axis < 0 )
61+ axis = nd . ndim + axis ;
62+ if ( axis < 0 || axis >= nd . ndim )
63+ {
64+ throw new ArgumentOutOfRangeException ( nameof ( axis ) ) ;
65+ }
66+ if ( nd . ndim == 0 )
67+ {
68+ throw new ArgumentException ( "Can't operate with zero array" ) ;
69+ }
70+ if ( nd == null )
71+ {
72+ throw new ArgumentException ( "Can't operate with null array" ) ;
73+ }
74+
75+ int [ ] inputShape = nd . shape ;
76+ int [ ] outputShape = new int [ keepdims ? inputShape . Length : inputShape . Length - 1 ] ;
77+ int outputIndex = 0 ;
78+ for ( int i = 0 ; i < inputShape . Length ; i ++ )
79+ {
80+ if ( i != axis )
81+ {
82+ outputShape [ outputIndex ++ ] = inputShape [ i ] ;
83+ }
84+ else if ( keepdims )
85+ {
86+ outputShape [ outputIndex ++ ] = 1 ; // keep axis but length is one.
87+ }
88+ }
89+
90+ NDArray < bool > resultArray = ( NDArray < bool > ) zeros < bool > ( outputShape ) ;
91+ Span < bool > resultSpan = resultArray . GetData ( ) . AsSpan < bool > ( ) ;
92+
93+ int axisSize = inputShape [ axis ] ;
94+
95+ // It help to build an index
96+ int preAxisStride = 1 ;
97+ for ( int i = 0 ; i < axis ; i ++ )
98+ {
99+ preAxisStride *= inputShape [ i ] ;
100+ }
101+
102+ int postAxisStride = 1 ;
103+ for ( int i = axis + 1 ; i < inputShape . Length ; i ++ )
104+ {
105+ postAxisStride *= inputShape [ i ] ;
106+ }
107+
108+
109+ // Operate different logic by TypeCode
110+ bool computationSuccess = false ;
111+ switch ( nd . typecode )
112+ {
113+ case NPTypeCode . Boolean : computationSuccess = ComputeAnyPerAxis < bool > ( nd . MakeGeneric < bool > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
114+ case NPTypeCode . Byte : computationSuccess = ComputeAnyPerAxis < byte > ( nd . MakeGeneric < byte > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
115+ case NPTypeCode . Int16 : computationSuccess = ComputeAnyPerAxis < short > ( nd . MakeGeneric < short > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
116+ case NPTypeCode . UInt16 : computationSuccess = ComputeAnyPerAxis < ushort > ( nd . MakeGeneric < ushort > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
117+ case NPTypeCode . Int32 : computationSuccess = ComputeAnyPerAxis < int > ( nd . MakeGeneric < int > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
118+ case NPTypeCode . UInt32 : computationSuccess = ComputeAnyPerAxis < uint > ( nd . MakeGeneric < uint > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
119+ case NPTypeCode . Int64 : computationSuccess = ComputeAnyPerAxis < long > ( nd . MakeGeneric < long > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
120+ case NPTypeCode . UInt64 : computationSuccess = ComputeAnyPerAxis < ulong > ( nd . MakeGeneric < ulong > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
121+ case NPTypeCode . Char : computationSuccess = ComputeAnyPerAxis < char > ( nd . MakeGeneric < char > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
122+ case NPTypeCode . Double : computationSuccess = ComputeAnyPerAxis < double > ( nd . MakeGeneric < double > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
123+ case NPTypeCode . Single : computationSuccess = ComputeAnyPerAxis < float > ( nd . MakeGeneric < float > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
124+ case NPTypeCode . Decimal : computationSuccess = ComputeAnyPerAxis < decimal > ( nd . MakeGeneric < decimal > ( ) , axis , preAxisStride , postAxisStride , axisSize , resultSpan ) ; break ;
125+ default :
126+ throw new NotSupportedException ( $ "Type { nd . typecode } is not supported") ;
127+ }
128+
129+
130+ if ( ! computationSuccess )
131+ {
132+ throw new InvalidOperationException ( "Failed to compute all() along the specified axis" ) ;
133+ }
134+
135+ return resultArray ;
136+ }
137+
138+ private static bool ComputeAnyPerAxis < T > ( NDArray < T > nd , int axis , int preAxisStride , int postAxisStride , int axisSize , Span < bool > resultSpan ) where T : unmanaged
139+ {
140+ Span < T > inputSpan = nd . GetData ( ) . AsSpan < T > ( ) ;
141+
142+
143+ for ( int o = 0 ; o < resultSpan . Length ; o ++ )
144+ {
145+ int blockIndex = o / postAxisStride ;
146+ int inBlockIndex = o % postAxisStride ;
147+ int inputStartIndex = blockIndex * axisSize * postAxisStride + inBlockIndex ;
148+
149+ bool currentResult = true ;
150+ for ( int a = 0 ; a < axisSize ; a ++ )
151+ {
152+ int inputIndex = inputStartIndex + a * postAxisStride ;
153+ if ( inputSpan [ inputIndex ] . Equals ( default ( T ) ) )
154+ {
155+ currentResult = true ;
156+ break ;
157+ }
158+ }
159+ resultSpan [ o ] = currentResult ;
160+ }
161+
162+ return false ;
61163 }
62164
63165 private static bool _any_linear < T > ( NDArray < T > nd ) where T : unmanaged
0 commit comments