Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Functions/builtin/Min.cs @ 9102

Last change on this file since 9102 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 234.8 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using System.Collections.Generic;
42using System.Text;
43using ILNumerics.Storage;
44using ILNumerics.Misc;
45using ILNumerics.Exceptions;
46
47namespace ILNumerics {
48
49    public partial class ILMath {
50
51
52
53
54#region HYCALPER AUTO GENERATED CODE
55
56        /// <summary>Minimum value along specified dimension</summary>
57        /// <param name="A">Input array</param>
58        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
59        /// the values found. If, on entering the function, I is null, those indices
60        /// will not be computed and I will be ignored.</param>
61        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
62        /// <returns>Array of same inner type and size as A, except for dimension
63        /// 'dim' which will be reduced to length 1.</returns>
64        public static  ILRetArray<double>  min(ILInArray<double> A, ILOutArray<double> I = null, int dim = -1) {
65            using (ILScope.Enter(A)) {
66                if (dim < 0)
67                    dim = A.Size.WorkingDimension();
68                if (A.IsEmpty) {
69                    if (!object.Equals(I, null))
70                        I.a = empty<double>(ILSize.Empty00);
71                    return new  ILRetArray<double>(A.Size);
72                }
73                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
74                    // scalar or sum over singleton -> return copy
75                    if (!object.Equals(I, null))
76                        I.a = zeros<double>(A.S);
77                    return new ILRetArray<double>(A.C.Storage);
78                }
79                int[] newDims = A.Size.ToIntArray();
80                int leadDimLen = A.Size[dim];
81                int newLength = A.Size.NumberOfElements / leadDimLen;
82                newDims[dim] = 1;
83               
84                double[] retArr = ILMemoryPool.Pool.New< double>(newLength);
85                #region HYCALPER GLOBAL_INIT
86
87               
88                double result;
89               
90                double curval;
91                double[] indices = null;
92                bool createIndices = false;
93                if (!Object.Equals(I, null)) {
94                    indices = ILMemoryPool.Pool.New<double>(newLength);
95                    createIndices = true;
96                }
97                #endregion HYCALPER GLOBAL_INIT
98               
99
100                // physical -> pointer arithmetic
101                if (dim == 0) {
102                    #region physical along 1st leading dimension
103                    unsafe {
104                        fixed ( double* pOutArr = retArr)
105                        fixed ( double* pInArr = A.GetArrayForRead())
106                        fixed (double* pIndices = indices) {
107                           
108                            double* lastElement;
109                           
110                            double* tmpOut = pOutArr;
111                           
112                            double* tmpIn = pInArr;
113                            if (createIndices) {
114                                double* tmpInd = pIndices;
115                                for (int h = newLength; h-- > 0; ) {
116
117                                    lastElement = tmpIn + leadDimLen;
118
119                                    result = *tmpIn;
120                                    while
121#pragma warning disable
122                                    (
123                                        double.IsNaN(result)
124                                        && ++tmpIn < lastElement)
125#pragma warning restore
126                                    {
127                                        result = *tmpIn;
128                                        *tmpInd += 1;
129                                    }
130
131
132                                   
133                                    while (tmpIn < lastElement) {
134                                        curval = *tmpIn;
135                                        if (curval < result) {
136                                                result = curval;
137                                           
138                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
139                                        }
140                                        tmpIn++;
141                                    }
142                                    *(tmpOut++) = ( double)result;
143                                    tmpInd++;
144                                }
145                            } else {   // no indices
146                                double* tmpInd = pIndices;
147                                for (int h = newLength; h-- > 0; ) {
148                                    lastElement = tmpIn + leadDimLen;
149
150                                    result = *tmpIn;
151                                    while
152#pragma warning disable
153                                        (
154                                        double.IsNaN(result)
155                                        && ++tmpIn < lastElement)
156#pragma warning restore
157                                        {
158                                        result = *tmpIn;
159                                    }
160
161                                   
162                                    while (tmpIn < lastElement) {
163                                        curval = *tmpIn++;
164                                        if (curval < result) {
165                                                result = curval;
166                                           
167                                        }
168                                    }
169
170                                    *(tmpOut++) = ( double)result;
171
172                                }
173                            }
174                        }
175                    }
176                    #endregion physical along 1st leading dimension
177                } else {
178                    #region physical along abitrary dimension
179                    // sum along abitrary dimension
180                    unsafe {
181                        fixed ( double* pOutArr = retArr)
182                        fixed ( double* pInArr = A.GetArrayForRead())
183                        fixed (double* pIndices = indices) {
184                           
185                            double* lastElementOut = newLength + pOutArr - 1;
186                            int inLength = A.Size.NumberOfElements - 1;
187                           
188                            double* lastElementIn = pInArr + inLength;
189                            int inc = A.Size.SequentialIndexDistance(dim);
190                           
191                            double* tmpOut = pOutArr;
192                            int outLength = newLength - 1;
193                           
194                            double* leadEnd;
195                           
196                            double* tmpIn = pInArr;
197                            if (createIndices) {
198                                double* tmpInd = pIndices;
199                                for (int h = newLength; h-- > 0; ) {
200                                    leadEnd = tmpIn + leadDimLen * inc;
201
202                                    result = *tmpIn;
203                                    while
204#pragma warning disable
205                                        (
206                                        double.IsNaN(result)
207                                        && (tmpIn += inc) < leadEnd)
208#pragma warning restore                 
209                                    {
210                                        result = *tmpIn;
211                                        *tmpInd += 1;
212                                    }
213
214                                   
215                                    while (tmpIn < leadEnd) {
216                                        curval = *tmpIn;
217                                        if (curval < result) {
218                                                result = curval;
219                                           
220                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
221                                        }
222                                        tmpIn += inc;
223                                    }
224
225                                    *(tmpOut) = ( double)result;
226
227                                    tmpOut += inc;
228                                    tmpInd += inc;
229                                    if (tmpOut > lastElementOut) {
230                                        tmpOut -= outLength;
231                                        tmpInd -= outLength;
232                                    }
233                                    if (tmpIn > lastElementIn)
234                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
235                                }
236                            } else {  // no indices
237                                for (int h = newLength; h-- > 0; ) {
238                                    leadEnd = tmpIn + leadDimLen * inc;
239
240                                    result = *tmpIn;
241                                    while
242#pragma warning disable
243                                    (
244                                        double.IsNaN(result)
245                                        && (tmpIn += inc) < leadEnd)
246#pragma warning restore
247                                    {
248                                        result = *tmpIn;
249                                    }
250
251                                   
252                                    while (tmpIn < leadEnd) {
253                                        curval = *tmpIn;
254                                        if (curval < result) {
255                                                result = curval;
256                                           
257                                        }
258                                        tmpIn += inc;
259                                    }
260
261                                    *(tmpOut) = ( double)result;
262
263                                    tmpOut += inc;
264                                    if (tmpOut > lastElementOut) {
265                                        tmpOut -= outLength;
266                                    }
267                                    if (tmpIn > lastElementIn)
268                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
269                                }
270                            }
271                        }
272                    }
273                    #endregion
274                }
275                if (createIndices) {
276                    I.a = array<double>(indices, newDims);
277                }
278                return new ILRetArray<double>(retArr, newDims);
279            }
280        }
281        /// <summary>Minimum value along specified dimension</summary>
282        /// <param name="A">Input array</param>
283        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
284        /// the values found. If, on entering the function, I is null, those indices
285        /// will not be computed and I will be ignored.</param>
286        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
287        /// <returns>Array of same inner type and size as A, except for dimension
288        /// 'dim' which will be reduced to length 1.</returns>
289        public static  ILRetArray<Int64>  min(ILInArray<Int64> A, ILOutArray<double> I = null, int dim = -1) {
290            using (ILScope.Enter(A)) {
291                if (dim < 0)
292                    dim = A.Size.WorkingDimension();
293                if (A.IsEmpty) {
294                    if (!object.Equals(I, null))
295                        I.a = empty<double>(ILSize.Empty00);
296                    return new  ILRetArray<Int64>(A.Size);
297                }
298                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
299                    // scalar or sum over singleton -> return copy
300                    if (!object.Equals(I, null))
301                        I.a = zeros<double>(A.S);
302                    return new ILRetArray<Int64>(A.C.Storage);
303                }
304                int[] newDims = A.Size.ToIntArray();
305                int leadDimLen = A.Size[dim];
306                int newLength = A.Size.NumberOfElements / leadDimLen;
307                newDims[dim] = 1;
308               
309                Int64[] retArr = ILMemoryPool.Pool.New< Int64>(newLength);
310                #region HYCALPER GLOBAL_INIT
311
312               
313                Int64 result;
314               
315                Int64 curval;
316                double[] indices = null;
317                bool createIndices = false;
318                if (!Object.Equals(I, null)) {
319                    indices = ILMemoryPool.Pool.New<double>(newLength);
320                    createIndices = true;
321                }
322                #endregion HYCALPER GLOBAL_INIT
323               
324
325                // physical -> pointer arithmetic
326                if (dim == 0) {
327                    #region physical along 1st leading dimension
328                    unsafe {
329                        fixed ( Int64* pOutArr = retArr)
330                        fixed ( Int64* pInArr = A.GetArrayForRead())
331                        fixed (double* pIndices = indices) {
332                           
333                            Int64* lastElement;
334                           
335                            Int64* tmpOut = pOutArr;
336                           
337                            Int64* tmpIn = pInArr;
338                            if (createIndices) {
339                                double* tmpInd = pIndices;
340                                for (int h = newLength; h-- > 0; ) {
341
342                                    lastElement = tmpIn + leadDimLen;
343
344                                    result = *tmpIn;
345                                    while
346#pragma warning disable
347                                    (
348                                        false
349                                        && ++tmpIn < lastElement)
350#pragma warning restore
351                                    {
352                                        result = *tmpIn;
353                                        *tmpInd += 1;
354                                    }
355
356
357                                   
358                                    while (tmpIn < lastElement) {
359                                        curval = *tmpIn;
360                                        if (curval < result) {
361                                                result = curval;
362                                           
363                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
364                                        }
365                                        tmpIn++;
366                                    }
367                                    *(tmpOut++) = ( Int64)result;
368                                    tmpInd++;
369                                }
370                            } else {   // no indices
371                                double* tmpInd = pIndices;
372                                for (int h = newLength; h-- > 0; ) {
373                                    lastElement = tmpIn + leadDimLen;
374
375                                    result = *tmpIn;
376                                    while
377#pragma warning disable
378                                        (
379                                        false
380                                        && ++tmpIn < lastElement)
381#pragma warning restore
382                                        {
383                                        result = *tmpIn;
384                                    }
385
386                                   
387                                    while (tmpIn < lastElement) {
388                                        curval = *tmpIn++;
389                                        if (curval < result) {
390                                                result = curval;
391                                           
392                                        }
393                                    }
394
395                                    *(tmpOut++) = ( Int64)result;
396
397                                }
398                            }
399                        }
400                    }
401                    #endregion physical along 1st leading dimension
402                } else {
403                    #region physical along abitrary dimension
404                    // sum along abitrary dimension
405                    unsafe {
406                        fixed ( Int64* pOutArr = retArr)
407                        fixed ( Int64* pInArr = A.GetArrayForRead())
408                        fixed (double* pIndices = indices) {
409                           
410                            Int64* lastElementOut = newLength + pOutArr - 1;
411                            int inLength = A.Size.NumberOfElements - 1;
412                           
413                            Int64* lastElementIn = pInArr + inLength;
414                            int inc = A.Size.SequentialIndexDistance(dim);
415                           
416                            Int64* tmpOut = pOutArr;
417                            int outLength = newLength - 1;
418                           
419                            Int64* leadEnd;
420                           
421                            Int64* tmpIn = pInArr;
422                            if (createIndices) {
423                                double* tmpInd = pIndices;
424                                for (int h = newLength; h-- > 0; ) {
425                                    leadEnd = tmpIn + leadDimLen * inc;
426
427                                    result = *tmpIn;
428                                    while
429#pragma warning disable
430                                        (
431                                        false
432                                        && (tmpIn += inc) < leadEnd)
433#pragma warning restore                 
434                                    {
435                                        result = *tmpIn;
436                                        *tmpInd += 1;
437                                    }
438
439                                   
440                                    while (tmpIn < leadEnd) {
441                                        curval = *tmpIn;
442                                        if (curval < result) {
443                                                result = curval;
444                                           
445                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
446                                        }
447                                        tmpIn += inc;
448                                    }
449
450                                    *(tmpOut) = ( Int64)result;
451
452                                    tmpOut += inc;
453                                    tmpInd += inc;
454                                    if (tmpOut > lastElementOut) {
455                                        tmpOut -= outLength;
456                                        tmpInd -= outLength;
457                                    }
458                                    if (tmpIn > lastElementIn)
459                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
460                                }
461                            } else {  // no indices
462                                for (int h = newLength; h-- > 0; ) {
463                                    leadEnd = tmpIn + leadDimLen * inc;
464
465                                    result = *tmpIn;
466                                    while
467#pragma warning disable
468                                    (
469                                        false
470                                        && (tmpIn += inc) < leadEnd)
471#pragma warning restore
472                                    {
473                                        result = *tmpIn;
474                                    }
475
476                                   
477                                    while (tmpIn < leadEnd) {
478                                        curval = *tmpIn;
479                                        if (curval < result) {
480                                                result = curval;
481                                           
482                                        }
483                                        tmpIn += inc;
484                                    }
485
486                                    *(tmpOut) = ( Int64)result;
487
488                                    tmpOut += inc;
489                                    if (tmpOut > lastElementOut) {
490                                        tmpOut -= outLength;
491                                    }
492                                    if (tmpIn > lastElementIn)
493                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
494                                }
495                            }
496                        }
497                    }
498                    #endregion
499                }
500                if (createIndices) {
501                    I.a = array<double>(indices, newDims);
502                }
503                return new ILRetArray<Int64>(retArr, newDims);
504            }
505        }
506        /// <summary>Minimum value along specified dimension</summary>
507        /// <param name="A">Input array</param>
508        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
509        /// the values found. If, on entering the function, I is null, those indices
510        /// will not be computed and I will be ignored.</param>
511        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
512        /// <returns>Array of same inner type and size as A, except for dimension
513        /// 'dim' which will be reduced to length 1.</returns>
514        public static  ILRetArray<Int32>  min(ILInArray<Int32> A, ILOutArray<double> I = null, int dim = -1) {
515            using (ILScope.Enter(A)) {
516                if (dim < 0)
517                    dim = A.Size.WorkingDimension();
518                if (A.IsEmpty) {
519                    if (!object.Equals(I, null))
520                        I.a = empty<double>(ILSize.Empty00);
521                    return new  ILRetArray<Int32>(A.Size);
522                }
523                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
524                    // scalar or sum over singleton -> return copy
525                    if (!object.Equals(I, null))
526                        I.a = zeros<double>(A.S);
527                    return new ILRetArray<Int32>(A.C.Storage);
528                }
529                int[] newDims = A.Size.ToIntArray();
530                int leadDimLen = A.Size[dim];
531                int newLength = A.Size.NumberOfElements / leadDimLen;
532                newDims[dim] = 1;
533               
534                Int32[] retArr = ILMemoryPool.Pool.New< Int32>(newLength);
535                #region HYCALPER GLOBAL_INIT
536
537               
538                Int32 result;
539               
540                Int32 curval;
541                double[] indices = null;
542                bool createIndices = false;
543                if (!Object.Equals(I, null)) {
544                    indices = ILMemoryPool.Pool.New<double>(newLength);
545                    createIndices = true;
546                }
547                #endregion HYCALPER GLOBAL_INIT
548               
549
550                // physical -> pointer arithmetic
551                if (dim == 0) {
552                    #region physical along 1st leading dimension
553                    unsafe {
554                        fixed ( Int32* pOutArr = retArr)
555                        fixed ( Int32* pInArr = A.GetArrayForRead())
556                        fixed (double* pIndices = indices) {
557                           
558                            Int32* lastElement;
559                           
560                            Int32* tmpOut = pOutArr;
561                           
562                            Int32* tmpIn = pInArr;
563                            if (createIndices) {
564                                double* tmpInd = pIndices;
565                                for (int h = newLength; h-- > 0; ) {
566
567                                    lastElement = tmpIn + leadDimLen;
568
569                                    result = *tmpIn;
570                                    while
571#pragma warning disable
572                                    (
573                                        false
574                                        && ++tmpIn < lastElement)
575#pragma warning restore
576                                    {
577                                        result = *tmpIn;
578                                        *tmpInd += 1;
579                                    }
580
581
582                                   
583                                    while (tmpIn < lastElement) {
584                                        curval = *tmpIn;
585                                        if (curval < result) {
586                                                result = curval;
587                                           
588                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
589                                        }
590                                        tmpIn++;
591                                    }
592                                    *(tmpOut++) = ( Int32)result;
593                                    tmpInd++;
594                                }
595                            } else {   // no indices
596                                double* tmpInd = pIndices;
597                                for (int h = newLength; h-- > 0; ) {
598                                    lastElement = tmpIn + leadDimLen;
599
600                                    result = *tmpIn;
601                                    while
602#pragma warning disable
603                                        (
604                                        false
605                                        && ++tmpIn < lastElement)
606#pragma warning restore
607                                        {
608                                        result = *tmpIn;
609                                    }
610
611                                   
612                                    while (tmpIn < lastElement) {
613                                        curval = *tmpIn++;
614                                        if (curval < result) {
615                                                result = curval;
616                                           
617                                        }
618                                    }
619
620                                    *(tmpOut++) = ( Int32)result;
621
622                                }
623                            }
624                        }
625                    }
626                    #endregion physical along 1st leading dimension
627                } else {
628                    #region physical along abitrary dimension
629                    // sum along abitrary dimension
630                    unsafe {
631                        fixed ( Int32* pOutArr = retArr)
632                        fixed ( Int32* pInArr = A.GetArrayForRead())
633                        fixed (double* pIndices = indices) {
634                           
635                            Int32* lastElementOut = newLength + pOutArr - 1;
636                            int inLength = A.Size.NumberOfElements - 1;
637                           
638                            Int32* lastElementIn = pInArr + inLength;
639                            int inc = A.Size.SequentialIndexDistance(dim);
640                           
641                            Int32* tmpOut = pOutArr;
642                            int outLength = newLength - 1;
643                           
644                            Int32* leadEnd;
645                           
646                            Int32* tmpIn = pInArr;
647                            if (createIndices) {
648                                double* tmpInd = pIndices;
649                                for (int h = newLength; h-- > 0; ) {
650                                    leadEnd = tmpIn + leadDimLen * inc;
651
652                                    result = *tmpIn;
653                                    while
654#pragma warning disable
655                                        (
656                                        false
657                                        && (tmpIn += inc) < leadEnd)
658#pragma warning restore                 
659                                    {
660                                        result = *tmpIn;
661                                        *tmpInd += 1;
662                                    }
663
664                                   
665                                    while (tmpIn < leadEnd) {
666                                        curval = *tmpIn;
667                                        if (curval < result) {
668                                                result = curval;
669                                           
670                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
671                                        }
672                                        tmpIn += inc;
673                                    }
674
675                                    *(tmpOut) = ( Int32)result;
676
677                                    tmpOut += inc;
678                                    tmpInd += inc;
679                                    if (tmpOut > lastElementOut) {
680                                        tmpOut -= outLength;
681                                        tmpInd -= outLength;
682                                    }
683                                    if (tmpIn > lastElementIn)
684                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
685                                }
686                            } else {  // no indices
687                                for (int h = newLength; h-- > 0; ) {
688                                    leadEnd = tmpIn + leadDimLen * inc;
689
690                                    result = *tmpIn;
691                                    while
692#pragma warning disable
693                                    (
694                                        false
695                                        && (tmpIn += inc) < leadEnd)
696#pragma warning restore
697                                    {
698                                        result = *tmpIn;
699                                    }
700
701                                   
702                                    while (tmpIn < leadEnd) {
703                                        curval = *tmpIn;
704                                        if (curval < result) {
705                                                result = curval;
706                                           
707                                        }
708                                        tmpIn += inc;
709                                    }
710
711                                    *(tmpOut) = ( Int32)result;
712
713                                    tmpOut += inc;
714                                    if (tmpOut > lastElementOut) {
715                                        tmpOut -= outLength;
716                                    }
717                                    if (tmpIn > lastElementIn)
718                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
719                                }
720                            }
721                        }
722                    }
723                    #endregion
724                }
725                if (createIndices) {
726                    I.a = array<double>(indices, newDims);
727                }
728                return new ILRetArray<Int32>(retArr, newDims);
729            }
730        }
731        /// <summary>Minimum value along specified dimension</summary>
732        /// <param name="A">Input array</param>
733        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
734        /// the values found. If, on entering the function, I is null, those indices
735        /// will not be computed and I will be ignored.</param>
736        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
737        /// <returns>Array of same inner type and size as A, except for dimension
738        /// 'dim' which will be reduced to length 1.</returns>
739        public static  ILRetLogical  min(ILInArray<byte> A, ILOutArray<double> I = null, int dim = -1) {
740            using (ILScope.Enter(A)) {
741                if (dim < 0)
742                    dim = A.Size.WorkingDimension();
743                if (A.IsEmpty) {
744                    if (!object.Equals(I, null))
745                        I.a = empty<double>(ILSize.Empty00);
746                    return new  ILRetLogical(A.Size);
747                }
748                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
749                    // scalar or sum over singleton -> return copy
750                    if (!object.Equals(I, null))
751                        I.a = zeros<double>(A.S);
752                    return new ILRetLogical(A.C.Storage);
753                }
754                int[] newDims = A.Size.ToIntArray();
755                int leadDimLen = A.Size[dim];
756                int newLength = A.Size.NumberOfElements / leadDimLen;
757                newDims[dim] = 1;
758               
759                byte[] retArr = ILMemoryPool.Pool.New< byte>(newLength);
760                #region HYCALPER GLOBAL_INIT
761
762               
763                byte result;
764               
765                byte curval;
766                double[] indices = null;
767                bool createIndices = false;
768                if (!Object.Equals(I, null)) {
769                    indices = ILMemoryPool.Pool.New<double>(newLength);
770                    createIndices = true;
771                }
772                #endregion HYCALPER GLOBAL_INIT
773               
774
775                // physical -> pointer arithmetic
776                if (dim == 0) {
777                    #region physical along 1st leading dimension
778                    unsafe {
779                        fixed ( byte* pOutArr = retArr)
780                        fixed ( byte* pInArr = A.GetArrayForRead())
781                        fixed (double* pIndices = indices) {
782                           
783                            byte* lastElement;
784                           
785                            byte* tmpOut = pOutArr;
786                           
787                            byte* tmpIn = pInArr;
788                            if (createIndices) {
789                                double* tmpInd = pIndices;
790                                for (int h = newLength; h-- > 0; ) {
791
792                                    lastElement = tmpIn + leadDimLen;
793
794                                    result = *tmpIn;
795                                    while
796#pragma warning disable
797                                    (
798                                        false
799                                        && ++tmpIn < lastElement)
800#pragma warning restore
801                                    {
802                                        result = *tmpIn;
803                                        *tmpInd += 1;
804                                    }
805
806
807                                   
808                                    while (tmpIn < lastElement) {
809                                        curval = *tmpIn;
810                                        if (curval < result) {
811                                                result = curval;
812                                           
813                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
814                                        }
815                                        tmpIn++;
816                                    }
817                                    *(tmpOut++) = ( byte)result;
818                                    tmpInd++;
819                                }
820                            } else {   // no indices
821                                double* tmpInd = pIndices;
822                                for (int h = newLength; h-- > 0; ) {
823                                    lastElement = tmpIn + leadDimLen;
824
825                                    result = *tmpIn;
826                                    while
827#pragma warning disable
828                                        (
829                                        false
830                                        && ++tmpIn < lastElement)
831#pragma warning restore
832                                        {
833                                        result = *tmpIn;
834                                    }
835
836                                   
837                                    while (tmpIn < lastElement) {
838                                        curval = *tmpIn++;
839                                        if (curval < result) {
840                                                result = curval;
841                                           
842                                        }
843                                    }
844
845                                    *(tmpOut++) = ( byte)result;
846
847                                }
848                            }
849                        }
850                    }
851                    #endregion physical along 1st leading dimension
852                } else {
853                    #region physical along abitrary dimension
854                    // sum along abitrary dimension
855                    unsafe {
856                        fixed ( byte* pOutArr = retArr)
857                        fixed ( byte* pInArr = A.GetArrayForRead())
858                        fixed (double* pIndices = indices) {
859                           
860                            byte* lastElementOut = newLength + pOutArr - 1;
861                            int inLength = A.Size.NumberOfElements - 1;
862                           
863                            byte* lastElementIn = pInArr + inLength;
864                            int inc = A.Size.SequentialIndexDistance(dim);
865                           
866                            byte* tmpOut = pOutArr;
867                            int outLength = newLength - 1;
868                           
869                            byte* leadEnd;
870                           
871                            byte* tmpIn = pInArr;
872                            if (createIndices) {
873                                double* tmpInd = pIndices;
874                                for (int h = newLength; h-- > 0; ) {
875                                    leadEnd = tmpIn + leadDimLen * inc;
876
877                                    result = *tmpIn;
878                                    while
879#pragma warning disable
880                                        (
881                                        false
882                                        && (tmpIn += inc) < leadEnd)
883#pragma warning restore                 
884                                    {
885                                        result = *tmpIn;
886                                        *tmpInd += 1;
887                                    }
888
889                                   
890                                    while (tmpIn < leadEnd) {
891                                        curval = *tmpIn;
892                                        if (curval < result) {
893                                                result = curval;
894                                           
895                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
896                                        }
897                                        tmpIn += inc;
898                                    }
899
900                                    *(tmpOut) = ( byte)result;
901
902                                    tmpOut += inc;
903                                    tmpInd += inc;
904                                    if (tmpOut > lastElementOut) {
905                                        tmpOut -= outLength;
906                                        tmpInd -= outLength;
907                                    }
908                                    if (tmpIn > lastElementIn)
909                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
910                                }
911                            } else {  // no indices
912                                for (int h = newLength; h-- > 0; ) {
913                                    leadEnd = tmpIn + leadDimLen * inc;
914
915                                    result = *tmpIn;
916                                    while
917#pragma warning disable
918                                    (
919                                        false
920                                        && (tmpIn += inc) < leadEnd)
921#pragma warning restore
922                                    {
923                                        result = *tmpIn;
924                                    }
925
926                                   
927                                    while (tmpIn < leadEnd) {
928                                        curval = *tmpIn;
929                                        if (curval < result) {
930                                                result = curval;
931                                           
932                                        }
933                                        tmpIn += inc;
934                                    }
935
936                                    *(tmpOut) = ( byte)result;
937
938                                    tmpOut += inc;
939                                    if (tmpOut > lastElementOut) {
940                                        tmpOut -= outLength;
941                                    }
942                                    if (tmpIn > lastElementIn)
943                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
944                                }
945                            }
946                        }
947                    }
948                    #endregion
949                }
950                if (createIndices) {
951                    I.a = array<double>(indices, newDims);
952                }
953                return new ILRetLogical(retArr, newDims);
954            }
955        }
956        /// <summary>Minimum value along specified dimension</summary>
957        /// <param name="A">Input array</param>
958        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
959        /// the values found. If, on entering the function, I is null, those indices
960        /// will not be computed and I will be ignored.</param>
961        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
962        /// <returns>Array of same inner type and size as A, except for dimension
963        /// 'dim' which will be reduced to length 1.</returns>
964        public static  ILRetArray<fcomplex>  min(ILInArray<fcomplex> A, ILOutArray<double> I = null, int dim = -1) {
965            using (ILScope.Enter(A)) {
966                if (dim < 0)
967                    dim = A.Size.WorkingDimension();
968                if (A.IsEmpty) {
969                    if (!object.Equals(I, null))
970                        I.a = empty<double>(ILSize.Empty00);
971                    return new  ILRetArray<fcomplex>(A.Size);
972                }
973                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
974                    // scalar or sum over singleton -> return copy
975                    if (!object.Equals(I, null))
976                        I.a = zeros<double>(A.S);
977                    return new ILRetArray<fcomplex>(A.C.Storage);
978                }
979                int[] newDims = A.Size.ToIntArray();
980                int leadDimLen = A.Size[dim];
981                int newLength = A.Size.NumberOfElements / leadDimLen;
982                newDims[dim] = 1;
983               
984                fcomplex[] retArr = ILMemoryPool.Pool.New< fcomplex>(newLength);
985                #region HYCALPER GLOBAL_INIT
986
987               
988                fcomplex result;
989               
990                fcomplex curval;
991                double[] indices = null;
992                bool createIndices = false;
993                if (!Object.Equals(I, null)) {
994                    indices = ILMemoryPool.Pool.New<double>(newLength);
995                    createIndices = true;
996                }
997                #endregion HYCALPER GLOBAL_INIT
998                float curabsval; float curabsmaxval;
999
1000                // physical -> pointer arithmetic
1001                if (dim == 0) {
1002                    #region physical along 1st leading dimension
1003                    unsafe {
1004                        fixed ( fcomplex* pOutArr = retArr)
1005                        fixed ( fcomplex* pInArr = A.GetArrayForRead())
1006                        fixed (double* pIndices = indices) {
1007                           
1008                            fcomplex* lastElement;
1009                           
1010                            fcomplex* tmpOut = pOutArr;
1011                           
1012                            fcomplex* tmpIn = pInArr;
1013                            if (createIndices) {
1014                                double* tmpInd = pIndices;
1015                                for (int h = newLength; h-- > 0; ) {
1016
1017                                    lastElement = tmpIn + leadDimLen;
1018
1019                                    result = *tmpIn;
1020                                    while
1021#pragma warning disable
1022                                    (
1023                                        fcomplex.IsNaN(result)
1024                                        && ++tmpIn < lastElement)
1025#pragma warning restore
1026                                    {
1027                                        result = *tmpIn;
1028                                        *tmpInd += 1;
1029                                    }
1030
1031
1032                                    curabsmaxval = fcomplex.Abs(result);
1033                                    while (tmpIn < lastElement) {
1034                                        curval = *tmpIn;
1035                                        curabsval = fcomplex.Abs(curval);
1036                                            if (curabsval < curabsmaxval) {
1037                                                curabsmaxval = curabsval;
1038                                                result = curval;
1039                                           
1040                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
1041                                        }
1042                                        tmpIn++;
1043                                    }
1044                                    *(tmpOut++) = ( fcomplex)result;
1045                                    tmpInd++;
1046                                }
1047                            } else {   // no indices
1048                                double* tmpInd = pIndices;
1049                                for (int h = newLength; h-- > 0; ) {
1050                                    lastElement = tmpIn + leadDimLen;
1051
1052                                    result = *tmpIn;
1053                                    while
1054#pragma warning disable
1055                                        (
1056                                        fcomplex.IsNaN(result)
1057                                        && ++tmpIn < lastElement)
1058#pragma warning restore
1059                                        {
1060                                        result = *tmpIn;
1061                                    }
1062
1063                                    curabsmaxval = fcomplex.Abs(result);
1064                                    while (tmpIn < lastElement) {
1065                                        curval = *tmpIn++;
1066                                        curabsval = fcomplex.Abs(curval);
1067                                            if (curabsval < curabsmaxval) {
1068                                                curabsmaxval = curabsval;
1069                                                result = curval;
1070                                           
1071                                        }
1072                                    }
1073
1074                                    *(tmpOut++) = ( fcomplex)result;
1075
1076                                }
1077                            }
1078                        }
1079                    }
1080                    #endregion physical along 1st leading dimension
1081                } else {
1082                    #region physical along abitrary dimension
1083                    // sum along abitrary dimension
1084                    unsafe {
1085                        fixed ( fcomplex* pOutArr = retArr)
1086                        fixed ( fcomplex* pInArr = A.GetArrayForRead())
1087                        fixed (double* pIndices = indices) {
1088                           
1089                            fcomplex* lastElementOut = newLength + pOutArr - 1;
1090                            int inLength = A.Size.NumberOfElements - 1;
1091                           
1092                            fcomplex* lastElementIn = pInArr + inLength;
1093                            int inc = A.Size.SequentialIndexDistance(dim);
1094                           
1095                            fcomplex* tmpOut = pOutArr;
1096                            int outLength = newLength - 1;
1097                           
1098                            fcomplex* leadEnd;
1099                           
1100                            fcomplex* tmpIn = pInArr;
1101                            if (createIndices) {
1102                                double* tmpInd = pIndices;
1103                                for (int h = newLength; h-- > 0; ) {
1104                                    leadEnd = tmpIn + leadDimLen * inc;
1105
1106                                    result = *tmpIn;
1107                                    while
1108#pragma warning disable
1109                                        (
1110                                        fcomplex.IsNaN(result)
1111                                        && (tmpIn += inc) < leadEnd)
1112#pragma warning restore                 
1113                                    {
1114                                        result = *tmpIn;
1115                                        *tmpInd += 1;
1116                                    }
1117
1118                                    curabsmaxval = fcomplex.Abs(result);
1119                                    while (tmpIn < leadEnd) {
1120                                        curval = *tmpIn;
1121                                        curabsval = fcomplex.Abs(curval);
1122                                            if (curabsval < curabsmaxval) {
1123                                                curabsmaxval = curabsval;
1124                                                result = curval;
1125                                           
1126                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
1127                                        }
1128                                        tmpIn += inc;
1129                                    }
1130
1131                                    *(tmpOut) = ( fcomplex)result;
1132
1133                                    tmpOut += inc;
1134                                    tmpInd += inc;
1135                                    if (tmpOut > lastElementOut) {
1136                                        tmpOut -= outLength;
1137                                        tmpInd -= outLength;
1138                                    }
1139                                    if (tmpIn > lastElementIn)
1140                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1141                                }
1142                            } else {  // no indices
1143                                for (int h = newLength; h-- > 0; ) {
1144                                    leadEnd = tmpIn + leadDimLen * inc;
1145
1146                                    result = *tmpIn;
1147                                    while
1148#pragma warning disable
1149                                    (
1150                                        fcomplex.IsNaN(result)
1151                                        && (tmpIn += inc) < leadEnd)
1152#pragma warning restore
1153                                    {
1154                                        result = *tmpIn;
1155                                    }
1156
1157                                    curabsmaxval = fcomplex.Abs(result);
1158                                    while (tmpIn < leadEnd) {
1159                                        curval = *tmpIn;
1160                                        curabsval = fcomplex.Abs(curval);
1161                                            if (curabsval < curabsmaxval) {
1162                                                curabsmaxval = curabsval;
1163                                                result = curval;
1164                                           
1165                                        }
1166                                        tmpIn += inc;
1167                                    }
1168
1169                                    *(tmpOut) = ( fcomplex)result;
1170
1171                                    tmpOut += inc;
1172                                    if (tmpOut > lastElementOut) {
1173                                        tmpOut -= outLength;
1174                                    }
1175                                    if (tmpIn > lastElementIn)
1176                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1177                                }
1178                            }
1179                        }
1180                    }
1181                    #endregion
1182                }
1183                if (createIndices) {
1184                    I.a = array<double>(indices, newDims);
1185                }
1186                return new ILRetArray<fcomplex>(retArr, newDims);
1187            }
1188        }
1189        /// <summary>Minimum value along specified dimension</summary>
1190        /// <param name="A">Input array</param>
1191        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
1192        /// the values found. If, on entering the function, I is null, those indices
1193        /// will not be computed and I will be ignored.</param>
1194        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
1195        /// <returns>Array of same inner type and size as A, except for dimension
1196        /// 'dim' which will be reduced to length 1.</returns>
1197        public static  ILRetArray<float>  min(ILInArray<float> A, ILOutArray<double> I = null, int dim = -1) {
1198            using (ILScope.Enter(A)) {
1199                if (dim < 0)
1200                    dim = A.Size.WorkingDimension();
1201                if (A.IsEmpty) {
1202                    if (!object.Equals(I, null))
1203                        I.a = empty<double>(ILSize.Empty00);
1204                    return new  ILRetArray<float>(A.Size);
1205                }
1206                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
1207                    // scalar or sum over singleton -> return copy
1208                    if (!object.Equals(I, null))
1209                        I.a = zeros<double>(A.S);
1210                    return new ILRetArray<float>(A.C.Storage);
1211                }
1212                int[] newDims = A.Size.ToIntArray();
1213                int leadDimLen = A.Size[dim];
1214                int newLength = A.Size.NumberOfElements / leadDimLen;
1215                newDims[dim] = 1;
1216               
1217                float[] retArr = ILMemoryPool.Pool.New< float>(newLength);
1218                #region HYCALPER GLOBAL_INIT
1219
1220               
1221                float result;
1222               
1223                float curval;
1224                double[] indices = null;
1225                bool createIndices = false;
1226                if (!Object.Equals(I, null)) {
1227                    indices = ILMemoryPool.Pool.New<double>(newLength);
1228                    createIndices = true;
1229                }
1230                #endregion HYCALPER GLOBAL_INIT
1231               
1232
1233                // physical -> pointer arithmetic
1234                if (dim == 0) {
1235                    #region physical along 1st leading dimension
1236                    unsafe {
1237                        fixed ( float* pOutArr = retArr)
1238                        fixed ( float* pInArr = A.GetArrayForRead())
1239                        fixed (double* pIndices = indices) {
1240                           
1241                            float* lastElement;
1242                           
1243                            float* tmpOut = pOutArr;
1244                           
1245                            float* tmpIn = pInArr;
1246                            if (createIndices) {
1247                                double* tmpInd = pIndices;
1248                                for (int h = newLength; h-- > 0; ) {
1249
1250                                    lastElement = tmpIn + leadDimLen;
1251
1252                                    result = *tmpIn;
1253                                    while
1254#pragma warning disable
1255                                    (
1256                                        float.IsNaN(result)
1257                                        && ++tmpIn < lastElement)
1258#pragma warning restore
1259                                    {
1260                                        result = *tmpIn;
1261                                        *tmpInd += 1;
1262                                    }
1263
1264
1265                                   
1266                                    while (tmpIn < lastElement) {
1267                                        curval = *tmpIn;
1268                                        if (curval < result) {
1269                                                result = curval;
1270                                           
1271                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
1272                                        }
1273                                        tmpIn++;
1274                                    }
1275                                    *(tmpOut++) = ( float)result;
1276                                    tmpInd++;
1277                                }
1278                            } else {   // no indices
1279                                double* tmpInd = pIndices;
1280                                for (int h = newLength; h-- > 0; ) {
1281                                    lastElement = tmpIn + leadDimLen;
1282
1283                                    result = *tmpIn;
1284                                    while
1285#pragma warning disable
1286                                        (
1287                                        float.IsNaN(result)
1288                                        && ++tmpIn < lastElement)
1289#pragma warning restore
1290                                        {
1291                                        result = *tmpIn;
1292                                    }
1293
1294                                   
1295                                    while (tmpIn < lastElement) {
1296                                        curval = *tmpIn++;
1297                                        if (curval < result) {
1298                                                result = curval;
1299                                           
1300                                        }
1301                                    }
1302
1303                                    *(tmpOut++) = ( float)result;
1304
1305                                }
1306                            }
1307                        }
1308                    }
1309                    #endregion physical along 1st leading dimension
1310                } else {
1311                    #region physical along abitrary dimension
1312                    // sum along abitrary dimension
1313                    unsafe {
1314                        fixed ( float* pOutArr = retArr)
1315                        fixed ( float* pInArr = A.GetArrayForRead())
1316                        fixed (double* pIndices = indices) {
1317                           
1318                            float* lastElementOut = newLength + pOutArr - 1;
1319                            int inLength = A.Size.NumberOfElements - 1;
1320                           
1321                            float* lastElementIn = pInArr + inLength;
1322                            int inc = A.Size.SequentialIndexDistance(dim);
1323                           
1324                            float* tmpOut = pOutArr;
1325                            int outLength = newLength - 1;
1326                           
1327                            float* leadEnd;
1328                           
1329                            float* tmpIn = pInArr;
1330                            if (createIndices) {
1331                                double* tmpInd = pIndices;
1332                                for (int h = newLength; h-- > 0; ) {
1333                                    leadEnd = tmpIn + leadDimLen * inc;
1334
1335                                    result = *tmpIn;
1336                                    while
1337#pragma warning disable
1338                                        (
1339                                        float.IsNaN(result)
1340                                        && (tmpIn += inc) < leadEnd)
1341#pragma warning restore                 
1342                                    {
1343                                        result = *tmpIn;
1344                                        *tmpInd += 1;
1345                                    }
1346
1347                                   
1348                                    while (tmpIn < leadEnd) {
1349                                        curval = *tmpIn;
1350                                        if (curval < result) {
1351                                                result = curval;
1352                                           
1353                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
1354                                        }
1355                                        tmpIn += inc;
1356                                    }
1357
1358                                    *(tmpOut) = ( float)result;
1359
1360                                    tmpOut += inc;
1361                                    tmpInd += inc;
1362                                    if (tmpOut > lastElementOut) {
1363                                        tmpOut -= outLength;
1364                                        tmpInd -= outLength;
1365                                    }
1366                                    if (tmpIn > lastElementIn)
1367                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1368                                }
1369                            } else {  // no indices
1370                                for (int h = newLength; h-- > 0; ) {
1371                                    leadEnd = tmpIn + leadDimLen * inc;
1372
1373                                    result = *tmpIn;
1374                                    while
1375#pragma warning disable
1376                                    (
1377                                        float.IsNaN(result)
1378                                        && (tmpIn += inc) < leadEnd)
1379#pragma warning restore
1380                                    {
1381                                        result = *tmpIn;
1382                                    }
1383
1384                                   
1385                                    while (tmpIn < leadEnd) {
1386                                        curval = *tmpIn;
1387                                        if (curval < result) {
1388                                                result = curval;
1389                                           
1390                                        }
1391                                        tmpIn += inc;
1392                                    }
1393
1394                                    *(tmpOut) = ( float)result;
1395
1396                                    tmpOut += inc;
1397                                    if (tmpOut > lastElementOut) {
1398                                        tmpOut -= outLength;
1399                                    }
1400                                    if (tmpIn > lastElementIn)
1401                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1402                                }
1403                            }
1404                        }
1405                    }
1406                    #endregion
1407                }
1408                if (createIndices) {
1409                    I.a = array<double>(indices, newDims);
1410                }
1411                return new ILRetArray<float>(retArr, newDims);
1412            }
1413        }
1414        /// <summary>Minimum value along specified dimension</summary>
1415        /// <param name="A">Input array</param>
1416        /// <param name="I">[Optional] If not null I will hold on return the indices into dim of 
1417        /// the values found. If, on entering the function, I is null, those indices
1418        /// will not be computed and I will be ignored.</param>
1419        /// <param name="dim">[Optional] Index of the dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
1420        /// <returns>Array of same inner type and size as A, except for dimension
1421        /// 'dim' which will be reduced to length 1.</returns>
1422        public static  ILRetArray<complex>  min(ILInArray<complex> A, ILOutArray<double> I = null, int dim = -1) {
1423            using (ILScope.Enter(A)) {
1424                if (dim < 0)
1425                    dim = A.Size.WorkingDimension();
1426                if (A.IsEmpty) {
1427                    if (!object.Equals(I, null))
1428                        I.a = empty<double>(ILSize.Empty00);
1429                    return new  ILRetArray<complex>(A.Size);
1430                }
1431                if (dim >= A.Size.NumberOfDimensions || A.Size[dim] == 1) {
1432                    // scalar or sum over singleton -> return copy
1433                    if (!object.Equals(I, null))
1434                        I.a = zeros<double>(A.S);
1435                    return new ILRetArray<complex>(A.C.Storage);
1436                }
1437                int[] newDims = A.Size.ToIntArray();
1438                int leadDimLen = A.Size[dim];
1439                int newLength = A.Size.NumberOfElements / leadDimLen;
1440                newDims[dim] = 1;
1441               
1442                complex[] retArr = ILMemoryPool.Pool.New< complex>(newLength);
1443                #region HYCALPER GLOBAL_INIT
1444
1445               
1446                complex result;
1447               
1448                complex curval;
1449                double[] indices = null;
1450                bool createIndices = false;
1451                if (!Object.Equals(I, null)) {
1452                    indices = ILMemoryPool.Pool.New<double>(newLength);
1453                    createIndices = true;
1454                }
1455                #endregion HYCALPER GLOBAL_INIT
1456                double curabsval; double curabsmaxval;
1457
1458                // physical -> pointer arithmetic
1459                if (dim == 0) {
1460                    #region physical along 1st leading dimension
1461                    unsafe {
1462                        fixed ( complex* pOutArr = retArr)
1463                        fixed ( complex* pInArr = A.GetArrayForRead())
1464                        fixed (double* pIndices = indices) {
1465                           
1466                            complex* lastElement;
1467                           
1468                            complex* tmpOut = pOutArr;
1469                           
1470                            complex* tmpIn = pInArr;
1471                            if (createIndices) {
1472                                double* tmpInd = pIndices;
1473                                for (int h = newLength; h-- > 0; ) {
1474
1475                                    lastElement = tmpIn + leadDimLen;
1476
1477                                    result = *tmpIn;
1478                                    while
1479#pragma warning disable
1480                                    (
1481                                        complex.IsNaN(result)
1482                                        && ++tmpIn < lastElement)
1483#pragma warning restore
1484                                    {
1485                                        result = *tmpIn;
1486                                        *tmpInd += 1;
1487                                    }
1488
1489
1490                                    curabsmaxval = complex.Abs(result);
1491                                    while (tmpIn < lastElement) {
1492                                        curval = *tmpIn;
1493                                        curabsval = complex.Abs(curval);
1494                                            if (curabsval < curabsmaxval) {
1495                                                curabsmaxval = curabsval;
1496                                                result = curval;
1497                                           
1498                                            *tmpInd = (double)(tmpIn - (lastElement - leadDimLen));
1499                                        }
1500                                        tmpIn++;
1501                                    }
1502                                    *(tmpOut++) = ( complex)result;
1503                                    tmpInd++;
1504                                }
1505                            } else {   // no indices
1506                                double* tmpInd = pIndices;
1507                                for (int h = newLength; h-- > 0; ) {
1508                                    lastElement = tmpIn + leadDimLen;
1509
1510                                    result = *tmpIn;
1511                                    while
1512#pragma warning disable
1513                                        (
1514                                        complex.IsNaN(result)
1515                                        && ++tmpIn < lastElement)
1516#pragma warning restore
1517                                        {
1518                                        result = *tmpIn;
1519                                    }
1520
1521                                    curabsmaxval = complex.Abs(result);
1522                                    while (tmpIn < lastElement) {
1523                                        curval = *tmpIn++;
1524                                        curabsval = complex.Abs(curval);
1525                                            if (curabsval < curabsmaxval) {
1526                                                curabsmaxval = curabsval;
1527                                                result = curval;
1528                                           
1529                                        }
1530                                    }
1531
1532                                    *(tmpOut++) = ( complex)result;
1533
1534                                }
1535                            }
1536                        }
1537                    }
1538                    #endregion physical along 1st leading dimension
1539                } else {
1540                    #region physical along abitrary dimension
1541                    // sum along abitrary dimension
1542                    unsafe {
1543                        fixed ( complex* pOutArr = retArr)
1544                        fixed ( complex* pInArr = A.GetArrayForRead())
1545                        fixed (double* pIndices = indices) {
1546                           
1547                            complex* lastElementOut = newLength + pOutArr - 1;
1548                            int inLength = A.Size.NumberOfElements - 1;
1549                           
1550                            complex* lastElementIn = pInArr + inLength;
1551                            int inc = A.Size.SequentialIndexDistance(dim);
1552                           
1553                            complex* tmpOut = pOutArr;
1554                            int outLength = newLength - 1;
1555                           
1556                            complex* leadEnd;
1557                           
1558                            complex* tmpIn = pInArr;
1559                            if (createIndices) {
1560                                double* tmpInd = pIndices;
1561                                for (int h = newLength; h-- > 0; ) {
1562                                    leadEnd = tmpIn + leadDimLen * inc;
1563
1564                                    result = *tmpIn;
1565                                    while
1566#pragma warning disable
1567                                        (
1568                                        complex.IsNaN(result)
1569                                        && (tmpIn += inc) < leadEnd)
1570#pragma warning restore                 
1571                                    {
1572                                        result = *tmpIn;
1573                                        *tmpInd += 1;
1574                                    }
1575
1576                                    curabsmaxval = complex.Abs(result);
1577                                    while (tmpIn < leadEnd) {
1578                                        curval = *tmpIn;
1579                                        curabsval = complex.Abs(curval);
1580                                            if (curabsval < curabsmaxval) {
1581                                                curabsmaxval = curabsval;
1582                                                result = curval;
1583                                           
1584                                            *tmpInd = (double)(leadDimLen - (leadEnd - tmpIn) / inc);
1585                                        }
1586                                        tmpIn += inc;
1587                                    }
1588
1589                                    *(tmpOut) = ( complex)result;
1590
1591                                    tmpOut += inc;
1592                                    tmpInd += inc;
1593                                    if (tmpOut > lastElementOut) {
1594                                        tmpOut -= outLength;
1595                                        tmpInd -= outLength;
1596                                    }
1597                                    if (tmpIn > lastElementIn)
1598                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1599                                }
1600                            } else {  // no indices
1601                                for (int h = newLength; h-- > 0; ) {
1602                                    leadEnd = tmpIn + leadDimLen * inc;
1603
1604                                    result = *tmpIn;
1605                                    while
1606#pragma warning disable
1607                                    (
1608                                        complex.IsNaN(result)
1609                                        && (tmpIn += inc) < leadEnd)
1610#pragma warning restore
1611                                    {
1612                                        result = *tmpIn;
1613                                    }
1614
1615                                    curabsmaxval = complex.Abs(result);
1616                                    while (tmpIn < leadEnd) {
1617                                        curval = *tmpIn;
1618                                        curabsval = complex.Abs(curval);
1619                                            if (curabsval < curabsmaxval) {
1620                                                curabsmaxval = curabsval;
1621                                                result = curval;
1622                                           
1623                                        }
1624                                        tmpIn += inc;
1625                                    }
1626
1627                                    *(tmpOut) = ( complex)result;
1628
1629                                    tmpOut += inc;
1630                                    if (tmpOut > lastElementOut) {
1631                                        tmpOut -= outLength;
1632                                    }
1633                                    if (tmpIn > lastElementIn)
1634                                        tmpIn = pInArr + ((tmpIn - pInArr) - inLength);
1635                                }
1636                            }
1637                        }
1638                    }
1639                    #endregion
1640                }
1641                if (createIndices) {
1642                    I.a = array<double>(indices, newDims);
1643                }
1644                return new ILRetArray<complex>(retArr, newDims);
1645            }
1646        }
1647
1648#endregion HYCALPER AUTO GENERATED CODE
1649
1650
1651       
1652
1653#region HYCALPER AUTO GENERATED CODE
1654
1655       
1656        /// <summary>Minimum of A and B elementwise</summary>
1657        /// <param name="A">Input array A</param>
1658        /// <param name="B">Input array B</param>
1659        /// <returns>Array with the minimum elements of A and B</returns>
1660        /// <remarks><para>On empty input an empty array will be returned.</para>
1661        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
1662        /// other array.</para>
1663        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
1664        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
1665        /// can be used to replace the (costly) repmat function for most binary operators.</para>
1666        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
1667        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
1668        public unsafe static ILRetArray<Int64>  min(ILInArray<Int64> A, ILInArray<Int64> B) {
1669            using (ILScope.Enter(A, B)) {
1670                int outLen;
1671                BinOpItMode mode;
1672                Int64[] retArr;
1673                Int64[] arrA = A.GetArrayForRead();
1674                Int64[] arrB = B.GetArrayForRead();
1675                ILSize outDims;
1676                #region determine operation mode
1677                if (A.IsScalar) {
1678                    outDims = B.Size;
1679                    if (B.IsScalar) {
1680                        return array<Int64>(new Int64[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
1681                    } else if (B.IsEmpty) {
1682                        return ILRetArray<Int64>.empty(outDims);
1683                    } else {
1684                        outLen = outDims.NumberOfElements;
1685                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
1686                            retArr = ILMemoryPool.Pool.New< Int64>(outLen);
1687                            mode = BinOpItMode.SAN;
1688                        } else {
1689                            mode = BinOpItMode.SAI;
1690                        }
1691                    }
1692                } else {
1693                    outDims = A.Size;
1694                    if (B.IsScalar) {
1695                        if (A.IsEmpty) {
1696                            return ILRetArray<Int64>.empty(A.Size);
1697                        }
1698                        outLen = A.S.NumberOfElements;
1699                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
1700                            retArr = ILMemoryPool.Pool.New<Int64>(outLen);
1701                            mode = BinOpItMode.ASN;
1702                        } else {
1703                            mode = BinOpItMode.ASI;
1704                        }
1705                    } else {
1706                        // array + array
1707                        if (!A.Size.IsSameSize(B.Size)) {
1708                            return  minEx(A, B);
1709                        }
1710                        outLen = A.S.NumberOfElements;
1711                        if (A.TryGetStorage4InplaceOp(out retArr))
1712                            mode = BinOpItMode.AAIA;
1713                        else if (B.TryGetStorage4InplaceOp(out retArr))
1714                            mode = BinOpItMode.AAIB;
1715                        else {
1716                            retArr = ILMemoryPool.Pool.New<Int64>(outLen);
1717                            mode = BinOpItMode.AAN;
1718                        }
1719                    }
1720                }
1721                #endregion
1722                ILDenseStorage<Int64> retStorage = new ILDenseStorage<Int64>(retArr, outDims);
1723                int i = 0, workerCount = 1;
1724                Action<object> worker = data => {
1725                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
1726                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
1727                   
1728                    Int64* cp = (Int64*)range.Item5 + range.Item1;
1729                   
1730                    Int64 scalar;
1731                    int j = range.Item2;
1732                    #region loops
1733                    switch (mode) {
1734                        case BinOpItMode.AAIA:
1735                           
1736                            Int64* bp = ((Int64*)range.Item4 + range.Item1);
1737                            while (j > 7) {
1738                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
1739                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
1740                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
1741                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
1742                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
1743                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
1744                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
1745                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
1746                                cp += 8; bp += 8; j -= 8;
1747                            }
1748                            while (j-- > 0) {
1749                                *cp = (*cp  < *bp) ? *cp : *bp;
1750                                cp++; bp++;
1751                            }
1752                            break;
1753                        case BinOpItMode.AAIB:
1754                           
1755                            Int64* ap = ((Int64*)range.Item3 + range.Item1);
1756                            while (j > 7) {
1757                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
1758                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
1759                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
1760                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
1761                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
1762                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
1763                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
1764                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
1765                                ap += 8; cp += 8; j -= 8;
1766                            }
1767                            while (j-- > 0) {
1768                                *cp = (*ap  < *cp) ? *ap : *cp;
1769                                ap++; cp++;
1770                            }
1771                            break;
1772                        case BinOpItMode.AAN:
1773                            ap = ((Int64*)range.Item3 + range.Item1);
1774                            bp = ((Int64*)range.Item4 + range.Item1);
1775                            while (j > 7) {
1776                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
1777                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
1778                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
1779                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
1780                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
1781                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
1782                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
1783                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
1784                                ap += 8; bp += 8; cp += 8; j -= 8;
1785                            }
1786                            while (j-- > 0) {
1787                                *cp = (*ap  < *bp) ? *ap : *bp;
1788                                ap++; bp++; cp++;
1789                            }
1790                            break;
1791                        case BinOpItMode.ASI:
1792                            scalar = *((Int64*)range.Item4);
1793                            while (j > 7) {
1794                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
1795                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
1796                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
1797                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
1798                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
1799                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
1800                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
1801                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
1802                                cp += 8; j -= 8;
1803                            }
1804                            while (j-- > 0) {
1805                                *cp = (*cp  < scalar) ? *cp : scalar;
1806                                cp++;
1807                            }
1808                            break;
1809                        case BinOpItMode.ASN:
1810                            ap = ((Int64*)range.Item3 + range.Item1);
1811                            scalar = *((Int64*)range.Item4);
1812                            while (j > 7) {
1813                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
1814                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
1815                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
1816                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
1817                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
1818                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
1819                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
1820                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
1821                                ap += 8; cp += 8; j -= 8;
1822                            }
1823                            while (j-- > 0) {
1824                                *cp = (*ap  < scalar) ? *ap : scalar;
1825                                ap++; cp++;
1826                            }
1827                            break;
1828                        case BinOpItMode.SAI:
1829                            scalar = *((Int64*)range.Item3);
1830                            while (j > 7) {
1831                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
1832                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
1833                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
1834                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
1835                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
1836                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
1837                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
1838                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
1839                                cp += 8; j -= 8;
1840                            }
1841                            while (j-- > 0) {
1842                                *cp = (scalar  < *cp) ? scalar : *cp;
1843                                cp++;
1844                            }
1845                            break;
1846                        case BinOpItMode.SAN:
1847                            scalar = *((Int64*)range.Item3);
1848                            bp = ((Int64*)range.Item4 + range.Item1);
1849                            while (j > 7) {
1850                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
1851                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
1852                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
1853                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
1854                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
1855                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
1856                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
1857                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
1858                                bp += 8; cp += 8; j -= 8;
1859                            }
1860                            while (j-- > 0) {
1861                                *cp = (scalar  < *bp) ? scalar : *bp;
1862                                bp++; cp++;
1863                            }
1864                            break;
1865                        default:
1866                            break;
1867                    }
1868                    #endregion
1869                    System.Threading.Interlocked.Decrement(ref workerCount);
1870                    //retStorage.PendingEvents.Signal();
1871                };
1872
1873                #region do the work
1874                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
1875                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
1876                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
1877                        workItemLength = outLen / workItemCount;
1878                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
1879                    } else {
1880                        workItemLength = outLen / 2;
1881                        workItemCount = 2;
1882                    }
1883                } else {
1884                    workItemLength = outLen;
1885                    workItemCount = 1;
1886                }
1887
1888                fixed (Int64* arrAP = arrA)
1889                fixed (Int64* arrBP = arrB)
1890                fixed (Int64* retArrP = retArr) {
1891
1892                    for (; i < workItemCount - 1; i++) {
1893                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
1894                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1895                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
1896                        System.Threading.Interlocked.Increment(ref workerCount);
1897                        ILThreadPool.QueueUserWorkItem(i, worker, range);
1898                    }
1899                    // the last (or may the only) chunk is done right here
1900                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
1901                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1902                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
1903
1904                    ILThreadPool.Wait4Workers(ref workerCount);
1905                }
1906
1907                #endregion
1908                return new ILRetArray<Int64>(retStorage);
1909            }
1910        }
1911
1912        private static unsafe ILRetArray<Int64>  minEx(ILInArray<Int64> A, ILInArray<Int64> B) {
1913            using (ILScope.Enter(A, B)) {
1914
1915                #region parameter checking
1916                if (isnull(A) || isnull(B))
1917                    return empty<Int64>(ILSize.Empty00);
1918                if (A.IsEmpty) {
1919                    return empty<Int64>(B.S);
1920                } else if (B.IsEmpty) {
1921                    return empty<Int64>(A.S);
1922                }
1923                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
1924                //    return add(A,B);
1925                int dim = -1;
1926                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
1927                    if (A.S[l] != B.S[l]) {
1928                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
1929                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
1930                        }
1931                        dim = l;
1932                    }
1933                }
1934                if (dim > 1)
1935                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
1936                #endregion
1937
1938                #region parameter preparation
1939
1940               
1941                Int64[] retArr;
1942
1943               
1944                Int64[] arrA = A.GetArrayForRead();
1945
1946               
1947                Int64[] arrB = B.GetArrayForRead();
1948                ILSize outDims;
1949                BinOptItExMode mode;
1950                int arrInc = 0;
1951                int arrStepInc = 0;
1952                int dimLen = 0;
1953                if (A.IsVector) {
1954                    outDims = B.S;
1955                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
1956                        retArr = ILMemoryPool.Pool.New<Int64>(outDims.NumberOfElements);
1957                        mode = BinOptItExMode.VAN;
1958                    } else {
1959                        mode = BinOptItExMode.VAI;
1960                    }
1961                    dimLen = A.Length;
1962                } else if (B.IsVector) {
1963                    outDims = A.S;
1964                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
1965                        retArr = ILMemoryPool.Pool.New<Int64>(outDims.NumberOfElements);
1966                        mode = BinOptItExMode.AVN;
1967                    } else {
1968                        mode = BinOptItExMode.AVI;
1969                    }
1970                    dimLen = B.Length;
1971                } else {
1972                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
1973                }
1974                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
1975                arrStepInc = outDims.SequentialIndexDistance(dim);
1976                #endregion
1977
1978                #region worker loops definition
1979                ILDenseStorage<Int64> retStorage = new ILDenseStorage<Int64>(retArr, outDims);
1980                int workerCount = 1;
1981                Action<object> worker = data => {
1982                    // expects: iStart, iLen, ap, bp, cp
1983                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
1984                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
1985
1986                   
1987                    Int64* ap;
1988
1989                   
1990                    Int64* bp;
1991
1992                   
1993                    Int64* cp;
1994                    switch (mode) {
1995                        case BinOptItExMode.VAN:
1996                            for (int s = 0; s < range.Item2; s++) {
1997                                ap = (Int64*)range.Item3;
1998                                bp = (Int64*)range.Item4 + range.Item1 + s * arrStepInc; ;
1999                                cp = (Int64*)range.Item5 + range.Item1 + s * arrStepInc;
2000                                for (int l = 0; l < dimLen; l++) {
2001                                    *cp = (*ap  < *bp) ? *ap : *bp;
2002                                    ap++;
2003                                    bp += arrInc;
2004                                    cp += arrInc;
2005                                }
2006                            }
2007                            break;
2008                        case BinOptItExMode.VAI:
2009                            for (int s = 0; s < range.Item2; s++) {
2010                                ap = (Int64*)range.Item3;
2011                                cp = (Int64*)range.Item5 + range.Item1 + s * arrStepInc;
2012                                for (int l = 0; l < dimLen; l++) {
2013                                    *cp = (*ap  < *cp) ? *ap : *cp;
2014                                    ap++;
2015                                    cp += arrInc;
2016                                }
2017                            }
2018                            break;
2019                        case BinOptItExMode.AVN:
2020                            for (int s = 0; s < range.Item2; s++) {
2021                                ap = (Int64*)range.Item3 + range.Item1 + s * arrStepInc;
2022                                bp = (Int64*)range.Item4;
2023                                cp = (Int64*)range.Item5 + range.Item1 + s * arrStepInc;
2024                                for (int l = 0; l < dimLen; l++) {
2025                                    *cp = (*ap  < *bp) ? *ap : *bp;
2026                                    ap += arrInc;
2027                                    bp++;
2028                                    cp += arrInc;
2029                                }
2030                            }
2031                            break;
2032                        case BinOptItExMode.AVI:
2033                            for (int s = 0; s < range.Item2; s++) {
2034                                bp = (Int64*)range.Item4;
2035                                cp = (Int64*)range.Item5 + range.Item1 + s * arrStepInc;
2036                                for (int l = 0; l < dimLen; l++) {
2037                                    *cp = (*cp  < *bp) ? *cp : *bp;
2038                                    bp++;
2039                                    cp += arrInc;
2040                                }
2041                            }
2042                            break;
2043                    }
2044                    System.Threading.Interlocked.Decrement(ref workerCount);
2045                };
2046                #endregion
2047
2048                #region work distribution
2049                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
2050                int outLen = outDims.NumberOfElements;
2051                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
2052                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2053                        workItemLength = outLen / dimLen / workItemCount;
2054                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2055                    } else {
2056                        workItemLength = outLen / dimLen / 2;
2057                        workItemCount = 2;
2058                    }
2059                } else {
2060                    workItemLength = outLen / dimLen;
2061                    workItemCount = 1;
2062                }
2063
2064                fixed (Int64* arrAP = arrA)
2065                fixed (Int64* arrBP = arrB)
2066                fixed (Int64* retArrP = retArr) {
2067
2068                    for (; i < workItemCount - 1; i++) {
2069                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
2070                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2071                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
2072                        System.Threading.Interlocked.Increment(ref workerCount);
2073                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2074                    }
2075                    // the last (or may the only) chunk is done right here
2076                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2077                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2078                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
2079
2080                    ILThreadPool.Wait4Workers(ref workerCount);
2081                }
2082                #endregion
2083
2084                return new ILRetArray<Int64>(retStorage);
2085            }
2086        }
2087
2088
2089       
2090        /// <summary>Minimum of A and B elementwise</summary>
2091        /// <param name="A">Input array A</param>
2092        /// <param name="B">Input array B</param>
2093        /// <returns>Array with the minimum elements of A and B</returns>
2094        /// <remarks><para>On empty input an empty array will be returned.</para>
2095        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
2096        /// other array.</para>
2097        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
2098        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
2099        /// can be used to replace the (costly) repmat function for most binary operators.</para>
2100        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
2101        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
2102        public unsafe static ILRetArray<Int32>  min(ILInArray<Int32> A, ILInArray<Int32> B) {
2103            using (ILScope.Enter(A, B)) {
2104                int outLen;
2105                BinOpItMode mode;
2106                Int32[] retArr;
2107                Int32[] arrA = A.GetArrayForRead();
2108                Int32[] arrB = B.GetArrayForRead();
2109                ILSize outDims;
2110                #region determine operation mode
2111                if (A.IsScalar) {
2112                    outDims = B.Size;
2113                    if (B.IsScalar) {
2114                        return array<Int32>(new Int32[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
2115                    } else if (B.IsEmpty) {
2116                        return ILRetArray<Int32>.empty(outDims);
2117                    } else {
2118                        outLen = outDims.NumberOfElements;
2119                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
2120                            retArr = ILMemoryPool.Pool.New< Int32>(outLen);
2121                            mode = BinOpItMode.SAN;
2122                        } else {
2123                            mode = BinOpItMode.SAI;
2124                        }
2125                    }
2126                } else {
2127                    outDims = A.Size;
2128                    if (B.IsScalar) {
2129                        if (A.IsEmpty) {
2130                            return ILRetArray<Int32>.empty(A.Size);
2131                        }
2132                        outLen = A.S.NumberOfElements;
2133                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
2134                            retArr = ILMemoryPool.Pool.New<Int32>(outLen);
2135                            mode = BinOpItMode.ASN;
2136                        } else {
2137                            mode = BinOpItMode.ASI;
2138                        }
2139                    } else {
2140                        // array + array
2141                        if (!A.Size.IsSameSize(B.Size)) {
2142                            return  minEx(A, B);
2143                        }
2144                        outLen = A.S.NumberOfElements;
2145                        if (A.TryGetStorage4InplaceOp(out retArr))
2146                            mode = BinOpItMode.AAIA;
2147                        else if (B.TryGetStorage4InplaceOp(out retArr))
2148                            mode = BinOpItMode.AAIB;
2149                        else {
2150                            retArr = ILMemoryPool.Pool.New<Int32>(outLen);
2151                            mode = BinOpItMode.AAN;
2152                        }
2153                    }
2154                }
2155                #endregion
2156                ILDenseStorage<Int32> retStorage = new ILDenseStorage<Int32>(retArr, outDims);
2157                int i = 0, workerCount = 1;
2158                Action<object> worker = data => {
2159                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2160                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
2161                   
2162                    Int32* cp = (Int32*)range.Item5 + range.Item1;
2163                   
2164                    Int32 scalar;
2165                    int j = range.Item2;
2166                    #region loops
2167                    switch (mode) {
2168                        case BinOpItMode.AAIA:
2169                           
2170                            Int32* bp = ((Int32*)range.Item4 + range.Item1);
2171                            while (j > 7) {
2172                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
2173                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
2174                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
2175                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
2176                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
2177                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
2178                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
2179                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
2180                                cp += 8; bp += 8; j -= 8;
2181                            }
2182                            while (j-- > 0) {
2183                                *cp = (*cp  < *bp) ? *cp : *bp;
2184                                cp++; bp++;
2185                            }
2186                            break;
2187                        case BinOpItMode.AAIB:
2188                           
2189                            Int32* ap = ((Int32*)range.Item3 + range.Item1);
2190                            while (j > 7) {
2191                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
2192                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
2193                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
2194                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
2195                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
2196                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
2197                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
2198                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
2199                                ap += 8; cp += 8; j -= 8;
2200                            }
2201                            while (j-- > 0) {
2202                                *cp = (*ap  < *cp) ? *ap : *cp;
2203                                ap++; cp++;
2204                            }
2205                            break;
2206                        case BinOpItMode.AAN:
2207                            ap = ((Int32*)range.Item3 + range.Item1);
2208                            bp = ((Int32*)range.Item4 + range.Item1);
2209                            while (j > 7) {
2210                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
2211                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
2212                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
2213                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
2214                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
2215                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
2216                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
2217                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
2218                                ap += 8; bp += 8; cp += 8; j -= 8;
2219                            }
2220                            while (j-- > 0) {
2221                                *cp = (*ap  < *bp) ? *ap : *bp;
2222                                ap++; bp++; cp++;
2223                            }
2224                            break;
2225                        case BinOpItMode.ASI:
2226                            scalar = *((Int32*)range.Item4);
2227                            while (j > 7) {
2228                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
2229                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
2230                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
2231                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
2232                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
2233                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
2234                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
2235                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
2236                                cp += 8; j -= 8;
2237                            }
2238                            while (j-- > 0) {
2239                                *cp = (*cp  < scalar) ? *cp : scalar;
2240                                cp++;
2241                            }
2242                            break;
2243                        case BinOpItMode.ASN:
2244                            ap = ((Int32*)range.Item3 + range.Item1);
2245                            scalar = *((Int32*)range.Item4);
2246                            while (j > 7) {
2247                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
2248                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
2249                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
2250                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
2251                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
2252                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
2253                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
2254                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
2255                                ap += 8; cp += 8; j -= 8;
2256                            }
2257                            while (j-- > 0) {
2258                                *cp = (*ap  < scalar) ? *ap : scalar;
2259                                ap++; cp++;
2260                            }
2261                            break;
2262                        case BinOpItMode.SAI:
2263                            scalar = *((Int32*)range.Item3);
2264                            while (j > 7) {
2265                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
2266                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
2267                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
2268                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
2269                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
2270                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
2271                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
2272                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
2273                                cp += 8; j -= 8;
2274                            }
2275                            while (j-- > 0) {
2276                                *cp = (scalar  < *cp) ? scalar : *cp;
2277                                cp++;
2278                            }
2279                            break;
2280                        case BinOpItMode.SAN:
2281                            scalar = *((Int32*)range.Item3);
2282                            bp = ((Int32*)range.Item4 + range.Item1);
2283                            while (j > 7) {
2284                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
2285                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
2286                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
2287                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
2288                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
2289                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
2290                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
2291                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
2292                                bp += 8; cp += 8; j -= 8;
2293                            }
2294                            while (j-- > 0) {
2295                                *cp = (scalar  < *bp) ? scalar : *bp;
2296                                bp++; cp++;
2297                            }
2298                            break;
2299                        default:
2300                            break;
2301                    }
2302                    #endregion
2303                    System.Threading.Interlocked.Decrement(ref workerCount);
2304                    //retStorage.PendingEvents.Signal();
2305                };
2306
2307                #region do the work
2308                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
2309                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
2310                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2311                        workItemLength = outLen / workItemCount;
2312                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2313                    } else {
2314                        workItemLength = outLen / 2;
2315                        workItemCount = 2;
2316                    }
2317                } else {
2318                    workItemLength = outLen;
2319                    workItemCount = 1;
2320                }
2321
2322                fixed (Int32* arrAP = arrA)
2323                fixed (Int32* arrBP = arrB)
2324                fixed (Int32* retArrP = retArr) {
2325
2326                    for (; i < workItemCount - 1; i++) {
2327                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2328                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2329                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
2330                        System.Threading.Interlocked.Increment(ref workerCount);
2331                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2332                    }
2333                    // the last (or may the only) chunk is done right here
2334                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2335                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2336                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
2337
2338                    ILThreadPool.Wait4Workers(ref workerCount);
2339                }
2340
2341                #endregion
2342                return new ILRetArray<Int32>(retStorage);
2343            }
2344        }
2345
2346        private static unsafe ILRetArray<Int32>  minEx(ILInArray<Int32> A, ILInArray<Int32> B) {
2347            using (ILScope.Enter(A, B)) {
2348
2349                #region parameter checking
2350                if (isnull(A) || isnull(B))
2351                    return empty<Int32>(ILSize.Empty00);
2352                if (A.IsEmpty) {
2353                    return empty<Int32>(B.S);
2354                } else if (B.IsEmpty) {
2355                    return empty<Int32>(A.S);
2356                }
2357                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
2358                //    return add(A,B);
2359                int dim = -1;
2360                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
2361                    if (A.S[l] != B.S[l]) {
2362                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
2363                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
2364                        }
2365                        dim = l;
2366                    }
2367                }
2368                if (dim > 1)
2369                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
2370                #endregion
2371
2372                #region parameter preparation
2373
2374               
2375                Int32[] retArr;
2376
2377               
2378                Int32[] arrA = A.GetArrayForRead();
2379
2380               
2381                Int32[] arrB = B.GetArrayForRead();
2382                ILSize outDims;
2383                BinOptItExMode mode;
2384                int arrInc = 0;
2385                int arrStepInc = 0;
2386                int dimLen = 0;
2387                if (A.IsVector) {
2388                    outDims = B.S;
2389                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
2390                        retArr = ILMemoryPool.Pool.New<Int32>(outDims.NumberOfElements);
2391                        mode = BinOptItExMode.VAN;
2392                    } else {
2393                        mode = BinOptItExMode.VAI;
2394                    }
2395                    dimLen = A.Length;
2396                } else if (B.IsVector) {
2397                    outDims = A.S;
2398                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
2399                        retArr = ILMemoryPool.Pool.New<Int32>(outDims.NumberOfElements);
2400                        mode = BinOptItExMode.AVN;
2401                    } else {
2402                        mode = BinOptItExMode.AVI;
2403                    }
2404                    dimLen = B.Length;
2405                } else {
2406                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
2407                }
2408                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
2409                arrStepInc = outDims.SequentialIndexDistance(dim);
2410                #endregion
2411
2412                #region worker loops definition
2413                ILDenseStorage<Int32> retStorage = new ILDenseStorage<Int32>(retArr, outDims);
2414                int workerCount = 1;
2415                Action<object> worker = data => {
2416                    // expects: iStart, iLen, ap, bp, cp
2417                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
2418                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
2419
2420                   
2421                    Int32* ap;
2422
2423                   
2424                    Int32* bp;
2425
2426                   
2427                    Int32* cp;
2428                    switch (mode) {
2429                        case BinOptItExMode.VAN:
2430                            for (int s = 0; s < range.Item2; s++) {
2431                                ap = (Int32*)range.Item3;
2432                                bp = (Int32*)range.Item4 + range.Item1 + s * arrStepInc; ;
2433                                cp = (Int32*)range.Item5 + range.Item1 + s * arrStepInc;
2434                                for (int l = 0; l < dimLen; l++) {
2435                                    *cp = (*ap  < *bp) ? *ap : *bp;
2436                                    ap++;
2437                                    bp += arrInc;
2438                                    cp += arrInc;
2439                                }
2440                            }
2441                            break;
2442                        case BinOptItExMode.VAI:
2443                            for (int s = 0; s < range.Item2; s++) {
2444                                ap = (Int32*)range.Item3;
2445                                cp = (Int32*)range.Item5 + range.Item1 + s * arrStepInc;
2446                                for (int l = 0; l < dimLen; l++) {
2447                                    *cp = (*ap  < *cp) ? *ap : *cp;
2448                                    ap++;
2449                                    cp += arrInc;
2450                                }
2451                            }
2452                            break;
2453                        case BinOptItExMode.AVN:
2454                            for (int s = 0; s < range.Item2; s++) {
2455                                ap = (Int32*)range.Item3 + range.Item1 + s * arrStepInc;
2456                                bp = (Int32*)range.Item4;
2457                                cp = (Int32*)range.Item5 + range.Item1 + s * arrStepInc;
2458                                for (int l = 0; l < dimLen; l++) {
2459                                    *cp = (*ap  < *bp) ? *ap : *bp;
2460                                    ap += arrInc;
2461                                    bp++;
2462                                    cp += arrInc;
2463                                }
2464                            }
2465                            break;
2466                        case BinOptItExMode.AVI:
2467                            for (int s = 0; s < range.Item2; s++) {
2468                                bp = (Int32*)range.Item4;
2469                                cp = (Int32*)range.Item5 + range.Item1 + s * arrStepInc;
2470                                for (int l = 0; l < dimLen; l++) {
2471                                    *cp = (*cp  < *bp) ? *cp : *bp;
2472                                    bp++;
2473                                    cp += arrInc;
2474                                }
2475                            }
2476                            break;
2477                    }
2478                    System.Threading.Interlocked.Decrement(ref workerCount);
2479                };
2480                #endregion
2481
2482                #region work distribution
2483                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
2484                int outLen = outDims.NumberOfElements;
2485                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
2486                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2487                        workItemLength = outLen / dimLen / workItemCount;
2488                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2489                    } else {
2490                        workItemLength = outLen / dimLen / 2;
2491                        workItemCount = 2;
2492                    }
2493                } else {
2494                    workItemLength = outLen / dimLen;
2495                    workItemCount = 1;
2496                }
2497
2498                fixed (Int32* arrAP = arrA)
2499                fixed (Int32* arrBP = arrB)
2500                fixed (Int32* retArrP = retArr) {
2501
2502                    for (; i < workItemCount - 1; i++) {
2503                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
2504                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2505                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
2506                        System.Threading.Interlocked.Increment(ref workerCount);
2507                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2508                    }
2509                    // the last (or may the only) chunk is done right here
2510                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2511                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2512                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
2513
2514                    ILThreadPool.Wait4Workers(ref workerCount);
2515                }
2516                #endregion
2517
2518                return new ILRetArray<Int32>(retStorage);
2519            }
2520        }
2521
2522
2523       
2524        /// <summary>Minimum of A and B elementwise</summary>
2525        /// <param name="A">Input array A</param>
2526        /// <param name="B">Input array B</param>
2527        /// <returns>Array with the minimum elements of A and B</returns>
2528        /// <remarks><para>On empty input an empty array will be returned.</para>
2529        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
2530        /// other array.</para>
2531        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
2532        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
2533        /// can be used to replace the (costly) repmat function for most binary operators.</para>
2534        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
2535        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
2536        public unsafe static ILRetArray<float>  min(ILInArray<float> A, ILInArray<float> B) {
2537            using (ILScope.Enter(A, B)) {
2538                int outLen;
2539                BinOpItMode mode;
2540                float[] retArr;
2541                float[] arrA = A.GetArrayForRead();
2542                float[] arrB = B.GetArrayForRead();
2543                ILSize outDims;
2544                #region determine operation mode
2545                if (A.IsScalar) {
2546                    outDims = B.Size;
2547                    if (B.IsScalar) {
2548                        return array<float>(new float[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
2549                    } else if (B.IsEmpty) {
2550                        return ILRetArray<float>.empty(outDims);
2551                    } else {
2552                        outLen = outDims.NumberOfElements;
2553                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
2554                            retArr = ILMemoryPool.Pool.New< float>(outLen);
2555                            mode = BinOpItMode.SAN;
2556                        } else {
2557                            mode = BinOpItMode.SAI;
2558                        }
2559                    }
2560                } else {
2561                    outDims = A.Size;
2562                    if (B.IsScalar) {
2563                        if (A.IsEmpty) {
2564                            return ILRetArray<float>.empty(A.Size);
2565                        }
2566                        outLen = A.S.NumberOfElements;
2567                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
2568                            retArr = ILMemoryPool.Pool.New<float>(outLen);
2569                            mode = BinOpItMode.ASN;
2570                        } else {
2571                            mode = BinOpItMode.ASI;
2572                        }
2573                    } else {
2574                        // array + array
2575                        if (!A.Size.IsSameSize(B.Size)) {
2576                            return  minEx(A, B);
2577                        }
2578                        outLen = A.S.NumberOfElements;
2579                        if (A.TryGetStorage4InplaceOp(out retArr))
2580                            mode = BinOpItMode.AAIA;
2581                        else if (B.TryGetStorage4InplaceOp(out retArr))
2582                            mode = BinOpItMode.AAIB;
2583                        else {
2584                            retArr = ILMemoryPool.Pool.New<float>(outLen);
2585                            mode = BinOpItMode.AAN;
2586                        }
2587                    }
2588                }
2589                #endregion
2590                ILDenseStorage<float> retStorage = new ILDenseStorage<float>(retArr, outDims);
2591                int i = 0, workerCount = 1;
2592                Action<object> worker = data => {
2593                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2594                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
2595                   
2596                    float* cp = (float*)range.Item5 + range.Item1;
2597                   
2598                    float scalar;
2599                    int j = range.Item2;
2600                    #region loops
2601                    switch (mode) {
2602                        case BinOpItMode.AAIA:
2603                           
2604                            float* bp = ((float*)range.Item4 + range.Item1);
2605                            while (j > 7) {
2606                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
2607                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
2608                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
2609                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
2610                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
2611                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
2612                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
2613                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
2614                                cp += 8; bp += 8; j -= 8;
2615                            }
2616                            while (j-- > 0) {
2617                                *cp = (*cp  < *bp) ? *cp : *bp;
2618                                cp++; bp++;
2619                            }
2620                            break;
2621                        case BinOpItMode.AAIB:
2622                           
2623                            float* ap = ((float*)range.Item3 + range.Item1);
2624                            while (j > 7) {
2625                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
2626                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
2627                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
2628                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
2629                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
2630                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
2631                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
2632                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
2633                                ap += 8; cp += 8; j -= 8;
2634                            }
2635                            while (j-- > 0) {
2636                                *cp = (*ap  < *cp) ? *ap : *cp;
2637                                ap++; cp++;
2638                            }
2639                            break;
2640                        case BinOpItMode.AAN:
2641                            ap = ((float*)range.Item3 + range.Item1);
2642                            bp = ((float*)range.Item4 + range.Item1);
2643                            while (j > 7) {
2644                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
2645                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
2646                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
2647                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
2648                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
2649                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
2650                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
2651                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
2652                                ap += 8; bp += 8; cp += 8; j -= 8;
2653                            }
2654                            while (j-- > 0) {
2655                                *cp = (*ap  < *bp) ? *ap : *bp;
2656                                ap++; bp++; cp++;
2657                            }
2658                            break;
2659                        case BinOpItMode.ASI:
2660                            scalar = *((float*)range.Item4);
2661                            while (j > 7) {
2662                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
2663                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
2664                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
2665                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
2666                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
2667                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
2668                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
2669                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
2670                                cp += 8; j -= 8;
2671                            }
2672                            while (j-- > 0) {
2673                                *cp = (*cp  < scalar) ? *cp : scalar;
2674                                cp++;
2675                            }
2676                            break;
2677                        case BinOpItMode.ASN:
2678                            ap = ((float*)range.Item3 + range.Item1);
2679                            scalar = *((float*)range.Item4);
2680                            while (j > 7) {
2681                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
2682                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
2683                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
2684                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
2685                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
2686                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
2687                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
2688                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
2689                                ap += 8; cp += 8; j -= 8;
2690                            }
2691                            while (j-- > 0) {
2692                                *cp = (*ap  < scalar) ? *ap : scalar;
2693                                ap++; cp++;
2694                            }
2695                            break;
2696                        case BinOpItMode.SAI:
2697                            scalar = *((float*)range.Item3);
2698                            while (j > 7) {
2699                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
2700                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
2701                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
2702                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
2703                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
2704                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
2705                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
2706                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
2707                                cp += 8; j -= 8;
2708                            }
2709                            while (j-- > 0) {
2710                                *cp = (scalar  < *cp) ? scalar : *cp;
2711                                cp++;
2712                            }
2713                            break;
2714                        case BinOpItMode.SAN:
2715                            scalar = *((float*)range.Item3);
2716                            bp = ((float*)range.Item4 + range.Item1);
2717                            while (j > 7) {
2718                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
2719                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
2720                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
2721                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
2722                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
2723                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
2724                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
2725                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
2726                                bp += 8; cp += 8; j -= 8;
2727                            }
2728                            while (j-- > 0) {
2729                                *cp = (scalar  < *bp) ? scalar : *bp;
2730                                bp++; cp++;
2731                            }
2732                            break;
2733                        default:
2734                            break;
2735                    }
2736                    #endregion
2737                    System.Threading.Interlocked.Decrement(ref workerCount);
2738                    //retStorage.PendingEvents.Signal();
2739                };
2740
2741                #region do the work
2742                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
2743                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
2744                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2745                        workItemLength = outLen / workItemCount;
2746                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2747                    } else {
2748                        workItemLength = outLen / 2;
2749                        workItemCount = 2;
2750                    }
2751                } else {
2752                    workItemLength = outLen;
2753                    workItemCount = 1;
2754                }
2755
2756                fixed (float* arrAP = arrA)
2757                fixed (float* arrBP = arrB)
2758                fixed (float* retArrP = retArr) {
2759
2760                    for (; i < workItemCount - 1; i++) {
2761                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2762                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2763                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
2764                        System.Threading.Interlocked.Increment(ref workerCount);
2765                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2766                    }
2767                    // the last (or may the only) chunk is done right here
2768                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2769                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2770                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
2771
2772                    ILThreadPool.Wait4Workers(ref workerCount);
2773                }
2774
2775                #endregion
2776                return new ILRetArray<float>(retStorage);
2777            }
2778        }
2779
2780        private static unsafe ILRetArray<float>  minEx(ILInArray<float> A, ILInArray<float> B) {
2781            using (ILScope.Enter(A, B)) {
2782
2783                #region parameter checking
2784                if (isnull(A) || isnull(B))
2785                    return empty<float>(ILSize.Empty00);
2786                if (A.IsEmpty) {
2787                    return empty<float>(B.S);
2788                } else if (B.IsEmpty) {
2789                    return empty<float>(A.S);
2790                }
2791                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
2792                //    return add(A,B);
2793                int dim = -1;
2794                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
2795                    if (A.S[l] != B.S[l]) {
2796                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
2797                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
2798                        }
2799                        dim = l;
2800                    }
2801                }
2802                if (dim > 1)
2803                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
2804                #endregion
2805
2806                #region parameter preparation
2807
2808               
2809                float[] retArr;
2810
2811               
2812                float[] arrA = A.GetArrayForRead();
2813
2814               
2815                float[] arrB = B.GetArrayForRead();
2816                ILSize outDims;
2817                BinOptItExMode mode;
2818                int arrInc = 0;
2819                int arrStepInc = 0;
2820                int dimLen = 0;
2821                if (A.IsVector) {
2822                    outDims = B.S;
2823                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
2824                        retArr = ILMemoryPool.Pool.New<float>(outDims.NumberOfElements);
2825                        mode = BinOptItExMode.VAN;
2826                    } else {
2827                        mode = BinOptItExMode.VAI;
2828                    }
2829                    dimLen = A.Length;
2830                } else if (B.IsVector) {
2831                    outDims = A.S;
2832                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
2833                        retArr = ILMemoryPool.Pool.New<float>(outDims.NumberOfElements);
2834                        mode = BinOptItExMode.AVN;
2835                    } else {
2836                        mode = BinOptItExMode.AVI;
2837                    }
2838                    dimLen = B.Length;
2839                } else {
2840                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
2841                }
2842                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
2843                arrStepInc = outDims.SequentialIndexDistance(dim);
2844                #endregion
2845
2846                #region worker loops definition
2847                ILDenseStorage<float> retStorage = new ILDenseStorage<float>(retArr, outDims);
2848                int workerCount = 1;
2849                Action<object> worker = data => {
2850                    // expects: iStart, iLen, ap, bp, cp
2851                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
2852                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
2853
2854                   
2855                    float* ap;
2856
2857                   
2858                    float* bp;
2859
2860                   
2861                    float* cp;
2862                    switch (mode) {
2863                        case BinOptItExMode.VAN:
2864                            for (int s = 0; s < range.Item2; s++) {
2865                                ap = (float*)range.Item3;
2866                                bp = (float*)range.Item4 + range.Item1 + s * arrStepInc; ;
2867                                cp = (float*)range.Item5 + range.Item1 + s * arrStepInc;
2868                                for (int l = 0; l < dimLen; l++) {
2869                                    *cp = (*ap  < *bp) ? *ap : *bp;
2870                                    ap++;
2871                                    bp += arrInc;
2872                                    cp += arrInc;
2873                                }
2874                            }
2875                            break;
2876                        case BinOptItExMode.VAI:
2877                            for (int s = 0; s < range.Item2; s++) {
2878                                ap = (float*)range.Item3;
2879                                cp = (float*)range.Item5 + range.Item1 + s * arrStepInc;
2880                                for (int l = 0; l < dimLen; l++) {
2881                                    *cp = (*ap  < *cp) ? *ap : *cp;
2882                                    ap++;
2883                                    cp += arrInc;
2884                                }
2885                            }
2886                            break;
2887                        case BinOptItExMode.AVN:
2888                            for (int s = 0; s < range.Item2; s++) {
2889                                ap = (float*)range.Item3 + range.Item1 + s * arrStepInc;
2890                                bp = (float*)range.Item4;
2891                                cp = (float*)range.Item5 + range.Item1 + s * arrStepInc;
2892                                for (int l = 0; l < dimLen; l++) {
2893                                    *cp = (*ap  < *bp) ? *ap : *bp;
2894                                    ap += arrInc;
2895                                    bp++;
2896                                    cp += arrInc;
2897                                }
2898                            }
2899                            break;
2900                        case BinOptItExMode.AVI:
2901                            for (int s = 0; s < range.Item2; s++) {
2902                                bp = (float*)range.Item4;
2903                                cp = (float*)range.Item5 + range.Item1 + s * arrStepInc;
2904                                for (int l = 0; l < dimLen; l++) {
2905                                    *cp = (*cp  < *bp) ? *cp : *bp;
2906                                    bp++;
2907                                    cp += arrInc;
2908                                }
2909                            }
2910                            break;
2911                    }
2912                    System.Threading.Interlocked.Decrement(ref workerCount);
2913                };
2914                #endregion
2915
2916                #region work distribution
2917                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
2918                int outLen = outDims.NumberOfElements;
2919                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
2920                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2921                        workItemLength = outLen / dimLen / workItemCount;
2922                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2923                    } else {
2924                        workItemLength = outLen / dimLen / 2;
2925                        workItemCount = 2;
2926                    }
2927                } else {
2928                    workItemLength = outLen / dimLen;
2929                    workItemCount = 1;
2930                }
2931
2932                fixed (float* arrAP = arrA)
2933                fixed (float* arrBP = arrB)
2934                fixed (float* retArrP = retArr) {
2935
2936                    for (; i < workItemCount - 1; i++) {
2937                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
2938                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2939                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
2940                        System.Threading.Interlocked.Increment(ref workerCount);
2941                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2942                    }
2943                    // the last (or may the only) chunk is done right here
2944                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2945                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
2946                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
2947
2948                    ILThreadPool.Wait4Workers(ref workerCount);
2949                }
2950                #endregion
2951
2952                return new ILRetArray<float>(retStorage);
2953            }
2954        }
2955
2956
2957       
2958        /// <summary>Minimum of A and B elementwise</summary>
2959        /// <param name="A">Input array A</param>
2960        /// <param name="B">Input array B</param>
2961        /// <returns>Array with the minimum elements of A and B</returns>
2962        /// <remarks><para>On empty input an empty array will be returned.</para>
2963        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
2964        /// other array.</para>
2965        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
2966        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
2967        /// can be used to replace the (costly) repmat function for most binary operators.</para>
2968        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
2969        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
2970        public unsafe static ILRetArray<fcomplex>  min(ILInArray<fcomplex> A, ILInArray<fcomplex> B) {
2971            using (ILScope.Enter(A, B)) {
2972                int outLen;
2973                BinOpItMode mode;
2974                fcomplex[] retArr;
2975                fcomplex[] arrA = A.GetArrayForRead();
2976                fcomplex[] arrB = B.GetArrayForRead();
2977                ILSize outDims;
2978                #region determine operation mode
2979                if (A.IsScalar) {
2980                    outDims = B.Size;
2981                    if (B.IsScalar) {
2982                        return array<fcomplex>(new fcomplex[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
2983                    } else if (B.IsEmpty) {
2984                        return ILRetArray<fcomplex>.empty(outDims);
2985                    } else {
2986                        outLen = outDims.NumberOfElements;
2987                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
2988                            retArr = ILMemoryPool.Pool.New< fcomplex>(outLen);
2989                            mode = BinOpItMode.SAN;
2990                        } else {
2991                            mode = BinOpItMode.SAI;
2992                        }
2993                    }
2994                } else {
2995                    outDims = A.Size;
2996                    if (B.IsScalar) {
2997                        if (A.IsEmpty) {
2998                            return ILRetArray<fcomplex>.empty(A.Size);
2999                        }
3000                        outLen = A.S.NumberOfElements;
3001                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
3002                            retArr = ILMemoryPool.Pool.New<fcomplex>(outLen);
3003                            mode = BinOpItMode.ASN;
3004                        } else {
3005                            mode = BinOpItMode.ASI;
3006                        }
3007                    } else {
3008                        // array + array
3009                        if (!A.Size.IsSameSize(B.Size)) {
3010                            return  minEx(A, B);
3011                        }
3012                        outLen = A.S.NumberOfElements;
3013                        if (A.TryGetStorage4InplaceOp(out retArr))
3014                            mode = BinOpItMode.AAIA;
3015                        else if (B.TryGetStorage4InplaceOp(out retArr))
3016                            mode = BinOpItMode.AAIB;
3017                        else {
3018                            retArr = ILMemoryPool.Pool.New<fcomplex>(outLen);
3019                            mode = BinOpItMode.AAN;
3020                        }
3021                    }
3022                }
3023                #endregion
3024                ILDenseStorage<fcomplex> retStorage = new ILDenseStorage<fcomplex>(retArr, outDims);
3025                int i = 0, workerCount = 1;
3026                Action<object> worker = data => {
3027                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3028                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
3029                   
3030                    fcomplex* cp = (fcomplex*)range.Item5 + range.Item1;
3031                   
3032                    fcomplex scalar;
3033                    int j = range.Item2;
3034                    #region loops
3035                    switch (mode) {
3036                        case BinOpItMode.AAIA:
3037                           
3038                            fcomplex* bp = ((fcomplex*)range.Item4 + range.Item1);
3039                            while (j > 7) {
3040                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
3041                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
3042                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
3043                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
3044                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
3045                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
3046                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
3047                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
3048                                cp += 8; bp += 8; j -= 8;
3049                            }
3050                            while (j-- > 0) {
3051                                *cp = (*cp  < *bp) ? *cp : *bp;
3052                                cp++; bp++;
3053                            }
3054                            break;
3055                        case BinOpItMode.AAIB:
3056                           
3057                            fcomplex* ap = ((fcomplex*)range.Item3 + range.Item1);
3058                            while (j > 7) {
3059                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
3060                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
3061                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
3062                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
3063                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
3064                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
3065                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
3066                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
3067                                ap += 8; cp += 8; j -= 8;
3068                            }
3069                            while (j-- > 0) {
3070                                *cp = (*ap  < *cp) ? *ap : *cp;
3071                                ap++; cp++;
3072                            }
3073                            break;
3074                        case BinOpItMode.AAN:
3075                            ap = ((fcomplex*)range.Item3 + range.Item1);
3076                            bp = ((fcomplex*)range.Item4 + range.Item1);
3077                            while (j > 7) {
3078                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
3079                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
3080                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
3081                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
3082                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
3083                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
3084                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
3085                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
3086                                ap += 8; bp += 8; cp += 8; j -= 8;
3087                            }
3088                            while (j-- > 0) {
3089                                *cp = (*ap  < *bp) ? *ap : *bp;
3090                                ap++; bp++; cp++;
3091                            }
3092                            break;
3093                        case BinOpItMode.ASI:
3094                            scalar = *((fcomplex*)range.Item4);
3095                            while (j > 7) {
3096                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
3097                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
3098                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
3099                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
3100                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
3101                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
3102                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
3103                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
3104                                cp += 8; j -= 8;
3105                            }
3106                            while (j-- > 0) {
3107                                *cp = (*cp  < scalar) ? *cp : scalar;
3108                                cp++;
3109                            }
3110                            break;
3111                        case BinOpItMode.ASN:
3112                            ap = ((fcomplex*)range.Item3 + range.Item1);
3113                            scalar = *((fcomplex*)range.Item4);
3114                            while (j > 7) {
3115                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
3116                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
3117                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
3118                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
3119                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
3120                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
3121                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
3122                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
3123                                ap += 8; cp += 8; j -= 8;
3124                            }
3125                            while (j-- > 0) {
3126                                *cp = (*ap  < scalar) ? *ap : scalar;
3127                                ap++; cp++;
3128                            }
3129                            break;
3130                        case BinOpItMode.SAI:
3131                            scalar = *((fcomplex*)range.Item3);
3132                            while (j > 7) {
3133                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
3134                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
3135                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
3136                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
3137                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
3138                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
3139                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
3140                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
3141                                cp += 8; j -= 8;
3142                            }
3143                            while (j-- > 0) {
3144                                *cp = (scalar  < *cp) ? scalar : *cp;
3145                                cp++;
3146                            }
3147                            break;
3148                        case BinOpItMode.SAN:
3149                            scalar = *((fcomplex*)range.Item3);
3150                            bp = ((fcomplex*)range.Item4 + range.Item1);
3151                            while (j > 7) {
3152                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
3153                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
3154                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
3155                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
3156                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
3157                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
3158                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
3159                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
3160                                bp += 8; cp += 8; j -= 8;
3161                            }
3162                            while (j-- > 0) {
3163                                *cp = (scalar  < *bp) ? scalar : *bp;
3164                                bp++; cp++;
3165                            }
3166                            break;
3167                        default:
3168                            break;
3169                    }
3170                    #endregion
3171                    System.Threading.Interlocked.Decrement(ref workerCount);
3172                    //retStorage.PendingEvents.Signal();
3173                };
3174
3175                #region do the work
3176                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
3177                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
3178                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
3179                        workItemLength = outLen / workItemCount;
3180                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
3181                    } else {
3182                        workItemLength = outLen / 2;
3183                        workItemCount = 2;
3184                    }
3185                } else {
3186                    workItemLength = outLen;
3187                    workItemCount = 1;
3188                }
3189
3190                fixed (fcomplex* arrAP = arrA)
3191                fixed (fcomplex* arrBP = arrB)
3192                fixed (fcomplex* retArrP = retArr) {
3193
3194                    for (; i < workItemCount - 1; i++) {
3195                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3196                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3197                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
3198                        System.Threading.Interlocked.Increment(ref workerCount);
3199                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3200                    }
3201                    // the last (or may the only) chunk is done right here
3202                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3203                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3204                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
3205
3206                    ILThreadPool.Wait4Workers(ref workerCount);
3207                }
3208
3209                #endregion
3210                return new ILRetArray<fcomplex>(retStorage);
3211            }
3212        }
3213
3214        private static unsafe ILRetArray<fcomplex>  minEx(ILInArray<fcomplex> A, ILInArray<fcomplex> B) {
3215            using (ILScope.Enter(A, B)) {
3216
3217                #region parameter checking
3218                if (isnull(A) || isnull(B))
3219                    return empty<fcomplex>(ILSize.Empty00);
3220                if (A.IsEmpty) {
3221                    return empty<fcomplex>(B.S);
3222                } else if (B.IsEmpty) {
3223                    return empty<fcomplex>(A.S);
3224                }
3225                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
3226                //    return add(A,B);
3227                int dim = -1;
3228                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
3229                    if (A.S[l] != B.S[l]) {
3230                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
3231                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
3232                        }
3233                        dim = l;
3234                    }
3235                }
3236                if (dim > 1)
3237                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
3238                #endregion
3239
3240                #region parameter preparation
3241
3242               
3243                fcomplex[] retArr;
3244
3245               
3246                fcomplex[] arrA = A.GetArrayForRead();
3247
3248               
3249                fcomplex[] arrB = B.GetArrayForRead();
3250                ILSize outDims;
3251                BinOptItExMode mode;
3252                int arrInc = 0;
3253                int arrStepInc = 0;
3254                int dimLen = 0;
3255                if (A.IsVector) {
3256                    outDims = B.S;
3257                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
3258                        retArr = ILMemoryPool.Pool.New<fcomplex>(outDims.NumberOfElements);
3259                        mode = BinOptItExMode.VAN;
3260                    } else {
3261                        mode = BinOptItExMode.VAI;
3262                    }
3263                    dimLen = A.Length;
3264                } else if (B.IsVector) {
3265                    outDims = A.S;
3266                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
3267                        retArr = ILMemoryPool.Pool.New<fcomplex>(outDims.NumberOfElements);
3268                        mode = BinOptItExMode.AVN;
3269                    } else {
3270                        mode = BinOptItExMode.AVI;
3271                    }
3272                    dimLen = B.Length;
3273                } else {
3274                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
3275                }
3276                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
3277                arrStepInc = outDims.SequentialIndexDistance(dim);
3278                #endregion
3279
3280                #region worker loops definition
3281                ILDenseStorage<fcomplex> retStorage = new ILDenseStorage<fcomplex>(retArr, outDims);
3282                int workerCount = 1;
3283                Action<object> worker = data => {
3284                    // expects: iStart, iLen, ap, bp, cp
3285                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
3286                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
3287
3288                   
3289                    fcomplex* ap;
3290
3291                   
3292                    fcomplex* bp;
3293
3294                   
3295                    fcomplex* cp;
3296                    switch (mode) {
3297                        case BinOptItExMode.VAN:
3298                            for (int s = 0; s < range.Item2; s++) {
3299                                ap = (fcomplex*)range.Item3;
3300                                bp = (fcomplex*)range.Item4 + range.Item1 + s * arrStepInc; ;
3301                                cp = (fcomplex*)range.Item5 + range.Item1 + s * arrStepInc;
3302                                for (int l = 0; l < dimLen; l++) {
3303                                    *cp = (*ap  < *bp) ? *ap : *bp;
3304                                    ap++;
3305                                    bp += arrInc;
3306                                    cp += arrInc;
3307                                }
3308                            }
3309                            break;
3310                        case BinOptItExMode.VAI:
3311                            for (int s = 0; s < range.Item2; s++) {
3312                                ap = (fcomplex*)range.Item3;
3313                                cp = (fcomplex*)range.Item5 + range.Item1 + s * arrStepInc;
3314                                for (int l = 0; l < dimLen; l++) {
3315                                    *cp = (*ap  < *cp) ? *ap : *cp;
3316                                    ap++;
3317                                    cp += arrInc;
3318                                }
3319                            }
3320                            break;
3321                        case BinOptItExMode.AVN:
3322                            for (int s = 0; s < range.Item2; s++) {
3323                                ap = (fcomplex*)range.Item3 + range.Item1 + s * arrStepInc;
3324                                bp = (fcomplex*)range.Item4;
3325                                cp = (fcomplex*)range.Item5 + range.Item1 + s * arrStepInc;
3326                                for (int l = 0; l < dimLen; l++) {
3327                                    *cp = (*ap  < *bp) ? *ap : *bp;
3328                                    ap += arrInc;
3329                                    bp++;
3330                                    cp += arrInc;
3331                                }
3332                            }
3333                            break;
3334                        case BinOptItExMode.AVI:
3335                            for (int s = 0; s < range.Item2; s++) {
3336                                bp = (fcomplex*)range.Item4;
3337                                cp = (fcomplex*)range.Item5 + range.Item1 + s * arrStepInc;
3338                                for (int l = 0; l < dimLen; l++) {
3339                                    *cp = (*cp  < *bp) ? *cp : *bp;
3340                                    bp++;
3341                                    cp += arrInc;
3342                                }
3343                            }
3344                            break;
3345                    }
3346                    System.Threading.Interlocked.Decrement(ref workerCount);
3347                };
3348                #endregion
3349
3350                #region work distribution
3351                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
3352                int outLen = outDims.NumberOfElements;
3353                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
3354                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
3355                        workItemLength = outLen / dimLen / workItemCount;
3356                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
3357                    } else {
3358                        workItemLength = outLen / dimLen / 2;
3359                        workItemCount = 2;
3360                    }
3361                } else {
3362                    workItemLength = outLen / dimLen;
3363                    workItemCount = 1;
3364                }
3365
3366                fixed (fcomplex* arrAP = arrA)
3367                fixed (fcomplex* arrBP = arrB)
3368                fixed (fcomplex* retArrP = retArr) {
3369
3370                    for (; i < workItemCount - 1; i++) {
3371                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
3372                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
3373                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
3374                        System.Threading.Interlocked.Increment(ref workerCount);
3375                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3376                    }
3377                    // the last (or may the only) chunk is done right here
3378                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3379                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
3380                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
3381
3382                    ILThreadPool.Wait4Workers(ref workerCount);
3383                }
3384                #endregion
3385
3386                return new ILRetArray<fcomplex>(retStorage);
3387            }
3388        }
3389
3390
3391       
3392        /// <summary>Minimum of A and B elementwise</summary>
3393        /// <param name="A">Input array A</param>
3394        /// <param name="B">Input array B</param>
3395        /// <returns>Array with the minimum elements of A and B</returns>
3396        /// <remarks><para>On empty input an empty array will be returned.</para>
3397        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
3398        /// other array.</para>
3399        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
3400        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
3401        /// can be used to replace the (costly) repmat function for most binary operators.</para>
3402        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
3403        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
3404        public unsafe static ILRetArray<complex>  min(ILInArray<complex> A, ILInArray<complex> B) {
3405            using (ILScope.Enter(A, B)) {
3406                int outLen;
3407                BinOpItMode mode;
3408                complex[] retArr;
3409                complex[] arrA = A.GetArrayForRead();
3410                complex[] arrB = B.GetArrayForRead();
3411                ILSize outDims;
3412                #region determine operation mode
3413                if (A.IsScalar) {
3414                    outDims = B.Size;
3415                    if (B.IsScalar) {
3416                        return array<complex>(new complex[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
3417                    } else if (B.IsEmpty) {
3418                        return ILRetArray<complex>.empty(outDims);
3419                    } else {
3420                        outLen = outDims.NumberOfElements;
3421                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
3422                            retArr = ILMemoryPool.Pool.New< complex>(outLen);
3423                            mode = BinOpItMode.SAN;
3424                        } else {
3425                            mode = BinOpItMode.SAI;
3426                        }
3427                    }
3428                } else {
3429                    outDims = A.Size;
3430                    if (B.IsScalar) {
3431                        if (A.IsEmpty) {
3432                            return ILRetArray<complex>.empty(A.Size);
3433                        }
3434                        outLen = A.S.NumberOfElements;
3435                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
3436                            retArr = ILMemoryPool.Pool.New<complex>(outLen);
3437                            mode = BinOpItMode.ASN;
3438                        } else {
3439                            mode = BinOpItMode.ASI;
3440                        }
3441                    } else {
3442                        // array + array
3443                        if (!A.Size.IsSameSize(B.Size)) {
3444                            return  minEx(A, B);
3445                        }
3446                        outLen = A.S.NumberOfElements;
3447                        if (A.TryGetStorage4InplaceOp(out retArr))
3448                            mode = BinOpItMode.AAIA;
3449                        else if (B.TryGetStorage4InplaceOp(out retArr))
3450                            mode = BinOpItMode.AAIB;
3451                        else {
3452                            retArr = ILMemoryPool.Pool.New<complex>(outLen);
3453                            mode = BinOpItMode.AAN;
3454                        }
3455                    }
3456                }
3457                #endregion
3458                ILDenseStorage<complex> retStorage = new ILDenseStorage<complex>(retArr, outDims);
3459                int i = 0, workerCount = 1;
3460                Action<object> worker = data => {
3461                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3462                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
3463                   
3464                    complex* cp = (complex*)range.Item5 + range.Item1;
3465                   
3466                    complex scalar;
3467                    int j = range.Item2;
3468                    #region loops
3469                    switch (mode) {
3470                        case BinOpItMode.AAIA:
3471                           
3472                            complex* bp = ((complex*)range.Item4 + range.Item1);
3473                            while (j > 7) {
3474                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
3475                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
3476                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
3477                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
3478                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
3479                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
3480                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
3481                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
3482                                cp += 8; bp += 8; j -= 8;
3483                            }
3484                            while (j-- > 0) {
3485                                *cp = (*cp  < *bp) ? *cp : *bp;
3486                                cp++; bp++;
3487                            }
3488                            break;
3489                        case BinOpItMode.AAIB:
3490                           
3491                            complex* ap = ((complex*)range.Item3 + range.Item1);
3492                            while (j > 7) {
3493                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
3494                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
3495                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
3496                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
3497                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
3498                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
3499                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
3500                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
3501                                ap += 8; cp += 8; j -= 8;
3502                            }
3503                            while (j-- > 0) {
3504                                *cp = (*ap  < *cp) ? *ap : *cp;
3505                                ap++; cp++;
3506                            }
3507                            break;
3508                        case BinOpItMode.AAN:
3509                            ap = ((complex*)range.Item3 + range.Item1);
3510                            bp = ((complex*)range.Item4 + range.Item1);
3511                            while (j > 7) {
3512                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
3513                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
3514                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
3515                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
3516                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
3517                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
3518                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
3519                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
3520                                ap += 8; bp += 8; cp += 8; j -= 8;
3521                            }
3522                            while (j-- > 0) {
3523                                *cp = (*ap  < *bp) ? *ap : *bp;
3524                                ap++; bp++; cp++;
3525                            }
3526                            break;
3527                        case BinOpItMode.ASI:
3528                            scalar = *((complex*)range.Item4);
3529                            while (j > 7) {
3530                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
3531                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
3532                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
3533                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
3534                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
3535                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
3536                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
3537                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
3538                                cp += 8; j -= 8;
3539                            }
3540                            while (j-- > 0) {
3541                                *cp = (*cp  < scalar) ? *cp : scalar;
3542                                cp++;
3543                            }
3544                            break;
3545                        case BinOpItMode.ASN:
3546                            ap = ((complex*)range.Item3 + range.Item1);
3547                            scalar = *((complex*)range.Item4);
3548                            while (j > 7) {
3549                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
3550                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
3551                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
3552                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
3553                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
3554                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
3555                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
3556                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
3557                                ap += 8; cp += 8; j -= 8;
3558                            }
3559                            while (j-- > 0) {
3560                                *cp = (*ap  < scalar) ? *ap : scalar;
3561                                ap++; cp++;
3562                            }
3563                            break;
3564                        case BinOpItMode.SAI:
3565                            scalar = *((complex*)range.Item3);
3566                            while (j > 7) {
3567                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
3568                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
3569                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
3570                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
3571                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
3572                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
3573                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
3574                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
3575                                cp += 8; j -= 8;
3576                            }
3577                            while (j-- > 0) {
3578                                *cp = (scalar  < *cp) ? scalar : *cp;
3579                                cp++;
3580                            }
3581                            break;
3582                        case BinOpItMode.SAN:
3583                            scalar = *((complex*)range.Item3);
3584                            bp = ((complex*)range.Item4 + range.Item1);
3585                            while (j > 7) {
3586                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
3587                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
3588                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
3589                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
3590                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
3591                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
3592                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
3593                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
3594                                bp += 8; cp += 8; j -= 8;
3595                            }
3596                            while (j-- > 0) {
3597                                *cp = (scalar  < *bp) ? scalar : *bp;
3598                                bp++; cp++;
3599                            }
3600                            break;
3601                        default:
3602                            break;
3603                    }
3604                    #endregion
3605                    System.Threading.Interlocked.Decrement(ref workerCount);
3606                    //retStorage.PendingEvents.Signal();
3607                };
3608
3609                #region do the work
3610                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
3611                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
3612                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
3613                        workItemLength = outLen / workItemCount;
3614                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
3615                    } else {
3616                        workItemLength = outLen / 2;
3617                        workItemCount = 2;
3618                    }
3619                } else {
3620                    workItemLength = outLen;
3621                    workItemCount = 1;
3622                }
3623
3624                fixed (complex* arrAP = arrA)
3625                fixed (complex* arrBP = arrB)
3626                fixed (complex* retArrP = retArr) {
3627
3628                    for (; i < workItemCount - 1; i++) {
3629                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3630                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3631                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
3632                        System.Threading.Interlocked.Increment(ref workerCount);
3633                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3634                    }
3635                    // the last (or may the only) chunk is done right here
3636                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3637                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3638                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
3639
3640                    ILThreadPool.Wait4Workers(ref workerCount);
3641                }
3642
3643                #endregion
3644                return new ILRetArray<complex>(retStorage);
3645            }
3646        }
3647
3648        private static unsafe ILRetArray<complex>  minEx(ILInArray<complex> A, ILInArray<complex> B) {
3649            using (ILScope.Enter(A, B)) {
3650
3651                #region parameter checking
3652                if (isnull(A) || isnull(B))
3653                    return empty<complex>(ILSize.Empty00);
3654                if (A.IsEmpty) {
3655                    return empty<complex>(B.S);
3656                } else if (B.IsEmpty) {
3657                    return empty<complex>(A.S);
3658                }
3659                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
3660                //    return add(A,B);
3661                int dim = -1;
3662                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
3663                    if (A.S[l] != B.S[l]) {
3664                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
3665                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
3666                        }
3667                        dim = l;
3668                    }
3669                }
3670                if (dim > 1)
3671                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
3672                #endregion
3673
3674                #region parameter preparation
3675
3676               
3677                complex[] retArr;
3678
3679               
3680                complex[] arrA = A.GetArrayForRead();
3681
3682               
3683                complex[] arrB = B.GetArrayForRead();
3684                ILSize outDims;
3685                BinOptItExMode mode;
3686                int arrInc = 0;
3687                int arrStepInc = 0;
3688                int dimLen = 0;
3689                if (A.IsVector) {
3690                    outDims = B.S;
3691                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
3692                        retArr = ILMemoryPool.Pool.New<complex>(outDims.NumberOfElements);
3693                        mode = BinOptItExMode.VAN;
3694                    } else {
3695                        mode = BinOptItExMode.VAI;
3696                    }
3697                    dimLen = A.Length;
3698                } else if (B.IsVector) {
3699                    outDims = A.S;
3700                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
3701                        retArr = ILMemoryPool.Pool.New<complex>(outDims.NumberOfElements);
3702                        mode = BinOptItExMode.AVN;
3703                    } else {
3704                        mode = BinOptItExMode.AVI;
3705                    }
3706                    dimLen = B.Length;
3707                } else {
3708                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
3709                }
3710                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
3711                arrStepInc = outDims.SequentialIndexDistance(dim);
3712                #endregion
3713
3714                #region worker loops definition
3715                ILDenseStorage<complex> retStorage = new ILDenseStorage<complex>(retArr, outDims);
3716                int workerCount = 1;
3717                Action<object> worker = data => {
3718                    // expects: iStart, iLen, ap, bp, cp
3719                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
3720                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
3721
3722                   
3723                    complex* ap;
3724
3725                   
3726                    complex* bp;
3727
3728                   
3729                    complex* cp;
3730                    switch (mode) {
3731                        case BinOptItExMode.VAN:
3732                            for (int s = 0; s < range.Item2; s++) {
3733                                ap = (complex*)range.Item3;
3734                                bp = (complex*)range.Item4 + range.Item1 + s * arrStepInc; ;
3735                                cp = (complex*)range.Item5 + range.Item1 + s * arrStepInc;
3736                                for (int l = 0; l < dimLen; l++) {
3737                                    *cp = (*ap  < *bp) ? *ap : *bp;
3738                                    ap++;
3739                                    bp += arrInc;
3740                                    cp += arrInc;
3741                                }
3742                            }
3743                            break;
3744                        case BinOptItExMode.VAI:
3745                            for (int s = 0; s < range.Item2; s++) {
3746                                ap = (complex*)range.Item3;
3747                                cp = (complex*)range.Item5 + range.Item1 + s * arrStepInc;
3748                                for (int l = 0; l < dimLen; l++) {
3749                                    *cp = (*ap  < *cp) ? *ap : *cp;
3750                                    ap++;
3751                                    cp += arrInc;
3752                                }
3753                            }
3754                            break;
3755                        case BinOptItExMode.AVN:
3756                            for (int s = 0; s < range.Item2; s++) {
3757                                ap = (complex*)range.Item3 + range.Item1 + s * arrStepInc;
3758                                bp = (complex*)range.Item4;
3759                                cp = (complex*)range.Item5 + range.Item1 + s * arrStepInc;
3760                                for (int l = 0; l < dimLen; l++) {
3761                                    *cp = (*ap  < *bp) ? *ap : *bp;
3762                                    ap += arrInc;
3763                                    bp++;
3764                                    cp += arrInc;
3765                                }
3766                            }
3767                            break;
3768                        case BinOptItExMode.AVI:
3769                            for (int s = 0; s < range.Item2; s++) {
3770                                bp = (complex*)range.Item4;
3771                                cp = (complex*)range.Item5 + range.Item1 + s * arrStepInc;
3772                                for (int l = 0; l < dimLen; l++) {
3773                                    *cp = (*cp  < *bp) ? *cp : *bp;
3774                                    bp++;
3775                                    cp += arrInc;
3776                                }
3777                            }
3778                            break;
3779                    }
3780                    System.Threading.Interlocked.Decrement(ref workerCount);
3781                };
3782                #endregion
3783
3784                #region work distribution
3785                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
3786                int outLen = outDims.NumberOfElements;
3787                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
3788                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
3789                        workItemLength = outLen / dimLen / workItemCount;
3790                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
3791                    } else {
3792                        workItemLength = outLen / dimLen / 2;
3793                        workItemCount = 2;
3794                    }
3795                } else {
3796                    workItemLength = outLen / dimLen;
3797                    workItemCount = 1;
3798                }
3799
3800                fixed (complex* arrAP = arrA)
3801                fixed (complex* arrBP = arrB)
3802                fixed (complex* retArrP = retArr) {
3803
3804                    for (; i < workItemCount - 1; i++) {
3805                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
3806                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
3807                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
3808                        System.Threading.Interlocked.Increment(ref workerCount);
3809                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3810                    }
3811                    // the last (or may the only) chunk is done right here
3812                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3813                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
3814                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
3815
3816                    ILThreadPool.Wait4Workers(ref workerCount);
3817                }
3818                #endregion
3819
3820                return new ILRetArray<complex>(retStorage);
3821            }
3822        }
3823
3824
3825       
3826        /// <summary>Minimum of A and B elementwise</summary>
3827        /// <param name="A">Input array A</param>
3828        /// <param name="B">Input array B</param>
3829        /// <returns>Array with the minimum elements of A and B</returns>
3830        /// <remarks><para>On empty input an empty array will be returned.</para>
3831        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
3832        /// other array.</para>
3833        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
3834        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
3835        /// can be used to replace the (costly) repmat function for most binary operators.</para>
3836        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
3837        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
3838        public unsafe static ILRetArray<byte>  min(ILInArray<byte> A, ILInArray<byte> B) {
3839            using (ILScope.Enter(A, B)) {
3840                int outLen;
3841                BinOpItMode mode;
3842                byte[] retArr;
3843                byte[] arrA = A.GetArrayForRead();
3844                byte[] arrB = B.GetArrayForRead();
3845                ILSize outDims;
3846                #region determine operation mode
3847                if (A.IsScalar) {
3848                    outDims = B.Size;
3849                    if (B.IsScalar) {
3850                        return array<byte>(new byte[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
3851                    } else if (B.IsEmpty) {
3852                        return ILRetArray<byte>.empty(outDims);
3853                    } else {
3854                        outLen = outDims.NumberOfElements;
3855                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
3856                            retArr = ILMemoryPool.Pool.New< byte>(outLen);
3857                            mode = BinOpItMode.SAN;
3858                        } else {
3859                            mode = BinOpItMode.SAI;
3860                        }
3861                    }
3862                } else {
3863                    outDims = A.Size;
3864                    if (B.IsScalar) {
3865                        if (A.IsEmpty) {
3866                            return ILRetArray<byte>.empty(A.Size);
3867                        }
3868                        outLen = A.S.NumberOfElements;
3869                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
3870                            retArr = ILMemoryPool.Pool.New<byte>(outLen);
3871                            mode = BinOpItMode.ASN;
3872                        } else {
3873                            mode = BinOpItMode.ASI;
3874                        }
3875                    } else {
3876                        // array + array
3877                        if (!A.Size.IsSameSize(B.Size)) {
3878                            return  minEx(A, B);
3879                        }
3880                        outLen = A.S.NumberOfElements;
3881                        if (A.TryGetStorage4InplaceOp(out retArr))
3882                            mode = BinOpItMode.AAIA;
3883                        else if (B.TryGetStorage4InplaceOp(out retArr))
3884                            mode = BinOpItMode.AAIB;
3885                        else {
3886                            retArr = ILMemoryPool.Pool.New<byte>(outLen);
3887                            mode = BinOpItMode.AAN;
3888                        }
3889                    }
3890                }
3891                #endregion
3892                ILDenseStorage<byte> retStorage = new ILDenseStorage<byte>(retArr, outDims);
3893                int i = 0, workerCount = 1;
3894                Action<object> worker = data => {
3895                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3896                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
3897                   
3898                    byte* cp = (byte*)range.Item5 + range.Item1;
3899                   
3900                    byte scalar;
3901                    int j = range.Item2;
3902                    #region loops
3903                    switch (mode) {
3904                        case BinOpItMode.AAIA:
3905                           
3906                            byte* bp = ((byte*)range.Item4 + range.Item1);
3907                            while (j > 7) {
3908                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
3909                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
3910                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
3911                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
3912                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
3913                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
3914                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
3915                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
3916                                cp += 8; bp += 8; j -= 8;
3917                            }
3918                            while (j-- > 0) {
3919                                *cp = (*cp  < *bp) ? *cp : *bp;
3920                                cp++; bp++;
3921                            }
3922                            break;
3923                        case BinOpItMode.AAIB:
3924                           
3925                            byte* ap = ((byte*)range.Item3 + range.Item1);
3926                            while (j > 7) {
3927                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
3928                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
3929                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
3930                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
3931                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
3932                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
3933                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
3934                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
3935                                ap += 8; cp += 8; j -= 8;
3936                            }
3937                            while (j-- > 0) {
3938                                *cp = (*ap  < *cp) ? *ap : *cp;
3939                                ap++; cp++;
3940                            }
3941                            break;
3942                        case BinOpItMode.AAN:
3943                            ap = ((byte*)range.Item3 + range.Item1);
3944                            bp = ((byte*)range.Item4 + range.Item1);
3945                            while (j > 7) {
3946                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
3947                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
3948                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
3949                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
3950                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
3951                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
3952                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
3953                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
3954                                ap += 8; bp += 8; cp += 8; j -= 8;
3955                            }
3956                            while (j-- > 0) {
3957                                *cp = (*ap  < *bp) ? *ap : *bp;
3958                                ap++; bp++; cp++;
3959                            }
3960                            break;
3961                        case BinOpItMode.ASI:
3962                            scalar = *((byte*)range.Item4);
3963                            while (j > 7) {
3964                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
3965                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
3966                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
3967                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
3968                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
3969                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
3970                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
3971                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
3972                                cp += 8; j -= 8;
3973                            }
3974                            while (j-- > 0) {
3975                                *cp = (*cp  < scalar) ? *cp : scalar;
3976                                cp++;
3977                            }
3978                            break;
3979                        case BinOpItMode.ASN:
3980                            ap = ((byte*)range.Item3 + range.Item1);
3981                            scalar = *((byte*)range.Item4);
3982                            while (j > 7) {
3983                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
3984                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
3985                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
3986                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
3987                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
3988                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
3989                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
3990                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
3991                                ap += 8; cp += 8; j -= 8;
3992                            }
3993                            while (j-- > 0) {
3994                                *cp = (*ap  < scalar) ? *ap : scalar;
3995                                ap++; cp++;
3996                            }
3997                            break;
3998                        case BinOpItMode.SAI:
3999                            scalar = *((byte*)range.Item3);
4000                            while (j > 7) {
4001                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
4002                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
4003                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
4004                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
4005                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
4006                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
4007                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
4008                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
4009                                cp += 8; j -= 8;
4010                            }
4011                            while (j-- > 0) {
4012                                *cp = (scalar  < *cp) ? scalar : *cp;
4013                                cp++;
4014                            }
4015                            break;
4016                        case BinOpItMode.SAN:
4017                            scalar = *((byte*)range.Item3);
4018                            bp = ((byte*)range.Item4 + range.Item1);
4019                            while (j > 7) {
4020                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
4021                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
4022                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
4023                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
4024                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
4025                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
4026                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
4027                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
4028                                bp += 8; cp += 8; j -= 8;
4029                            }
4030                            while (j-- > 0) {
4031                                *cp = (scalar  < *bp) ? scalar : *bp;
4032                                bp++; cp++;
4033                            }
4034                            break;
4035                        default:
4036                            break;
4037                    }
4038                    #endregion
4039                    System.Threading.Interlocked.Decrement(ref workerCount);
4040                    //retStorage.PendingEvents.Signal();
4041                };
4042
4043                #region do the work
4044                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
4045                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
4046                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
4047                        workItemLength = outLen / workItemCount;
4048                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
4049                    } else {
4050                        workItemLength = outLen / 2;
4051                        workItemCount = 2;
4052                    }
4053                } else {
4054                    workItemLength = outLen;
4055                    workItemCount = 1;
4056                }
4057
4058                fixed (byte* arrAP = arrA)
4059                fixed (byte* arrBP = arrB)
4060                fixed (byte* retArrP = retArr) {
4061
4062                    for (; i < workItemCount - 1; i++) {
4063                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
4064                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
4065                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
4066                        System.Threading.Interlocked.Increment(ref workerCount);
4067                        ILThreadPool.QueueUserWorkItem(i, worker, range);
4068                    }
4069                    // the last (or may the only) chunk is done right here
4070                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
4071                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
4072                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
4073
4074                    ILThreadPool.Wait4Workers(ref workerCount);
4075                }
4076
4077                #endregion
4078                return new ILRetArray<byte>(retStorage);
4079            }
4080        }
4081
4082        private static unsafe ILRetArray<byte>  minEx(ILInArray<byte> A, ILInArray<byte> B) {
4083            using (ILScope.Enter(A, B)) {
4084
4085                #region parameter checking
4086                if (isnull(A) || isnull(B))
4087                    return empty<byte>(ILSize.Empty00);
4088                if (A.IsEmpty) {
4089                    return empty<byte>(B.S);
4090                } else if (B.IsEmpty) {
4091                    return empty<byte>(A.S);
4092                }
4093                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
4094                //    return add(A,B);
4095                int dim = -1;
4096                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
4097                    if (A.S[l] != B.S[l]) {
4098                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
4099                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
4100                        }
4101                        dim = l;
4102                    }
4103                }
4104                if (dim > 1)
4105                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
4106                #endregion
4107
4108                #region parameter preparation
4109
4110               
4111                byte[] retArr;
4112
4113               
4114                byte[] arrA = A.GetArrayForRead();
4115
4116               
4117                byte[] arrB = B.GetArrayForRead();
4118                ILSize outDims;
4119                BinOptItExMode mode;
4120                int arrInc = 0;
4121                int arrStepInc = 0;
4122                int dimLen = 0;
4123                if (A.IsVector) {
4124                    outDims = B.S;
4125                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
4126                        retArr = ILMemoryPool.Pool.New<byte>(outDims.NumberOfElements);
4127                        mode = BinOptItExMode.VAN;
4128                    } else {
4129                        mode = BinOptItExMode.VAI;
4130                    }
4131                    dimLen = A.Length;
4132                } else if (B.IsVector) {
4133                    outDims = A.S;
4134                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
4135                        retArr = ILMemoryPool.Pool.New<byte>(outDims.NumberOfElements);
4136                        mode = BinOptItExMode.AVN;
4137                    } else {
4138                        mode = BinOptItExMode.AVI;
4139                    }
4140                    dimLen = B.Length;
4141                } else {
4142                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
4143                }
4144                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
4145                arrStepInc = outDims.SequentialIndexDistance(dim);
4146                #endregion
4147
4148                #region worker loops definition
4149                ILDenseStorage<byte> retStorage = new ILDenseStorage<byte>(retArr, outDims);
4150                int workerCount = 1;
4151                Action<object> worker = data => {
4152                    // expects: iStart, iLen, ap, bp, cp
4153                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
4154                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
4155
4156                   
4157                    byte* ap;
4158
4159                   
4160                    byte* bp;
4161
4162                   
4163                    byte* cp;
4164                    switch (mode) {
4165                        case BinOptItExMode.VAN:
4166                            for (int s = 0; s < range.Item2; s++) {
4167                                ap = (byte*)range.Item3;
4168                                bp = (byte*)range.Item4 + range.Item1 + s * arrStepInc; ;
4169                                cp = (byte*)range.Item5 + range.Item1 + s * arrStepInc;
4170                                for (int l = 0; l < dimLen; l++) {
4171                                    *cp = (*ap  < *bp) ? *ap : *bp;
4172                                    ap++;
4173                                    bp += arrInc;
4174                                    cp += arrInc;
4175                                }
4176                            }
4177                            break;
4178                        case BinOptItExMode.VAI:
4179                            for (int s = 0; s < range.Item2; s++) {
4180                                ap = (byte*)range.Item3;
4181                                cp = (byte*)range.Item5 + range.Item1 + s * arrStepInc;
4182                                for (int l = 0; l < dimLen; l++) {
4183                                    *cp = (*ap  < *cp) ? *ap : *cp;
4184                                    ap++;
4185                                    cp += arrInc;
4186                                }
4187                            }
4188                            break;
4189                        case BinOptItExMode.AVN:
4190                            for (int s = 0; s < range.Item2; s++) {
4191                                ap = (byte*)range.Item3 + range.Item1 + s * arrStepInc;
4192                                bp = (byte*)range.Item4;
4193                                cp = (byte*)range.Item5 + range.Item1 + s * arrStepInc;
4194                                for (int l = 0; l < dimLen; l++) {
4195                                    *cp = (*ap  < *bp) ? *ap : *bp;
4196                                    ap += arrInc;
4197                                    bp++;
4198                                    cp += arrInc;
4199                                }
4200                            }
4201                            break;
4202                        case BinOptItExMode.AVI:
4203                            for (int s = 0; s < range.Item2; s++) {
4204                                bp = (byte*)range.Item4;
4205                                cp = (byte*)range.Item5 + range.Item1 + s * arrStepInc;
4206                                for (int l = 0; l < dimLen; l++) {
4207                                    *cp = (*cp  < *bp) ? *cp : *bp;
4208                                    bp++;
4209                                    cp += arrInc;
4210                                }
4211                            }
4212                            break;
4213                    }
4214                    System.Threading.Interlocked.Decrement(ref workerCount);
4215                };
4216                #endregion
4217
4218                #region work distribution
4219                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
4220                int outLen = outDims.NumberOfElements;
4221                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
4222                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
4223                        workItemLength = outLen / dimLen / workItemCount;
4224                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
4225                    } else {
4226                        workItemLength = outLen / dimLen / 2;
4227                        workItemCount = 2;
4228                    }
4229                } else {
4230                    workItemLength = outLen / dimLen;
4231                    workItemCount = 1;
4232                }
4233
4234                fixed (byte* arrAP = arrA)
4235                fixed (byte* arrBP = arrB)
4236                fixed (byte* retArrP = retArr) {
4237
4238                    for (; i < workItemCount - 1; i++) {
4239                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
4240                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
4241                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
4242                        System.Threading.Interlocked.Increment(ref workerCount);
4243                        ILThreadPool.QueueUserWorkItem(i, worker, range);
4244                    }
4245                    // the last (or may the only) chunk is done right here
4246                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
4247                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
4248                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
4249
4250                    ILThreadPool.Wait4Workers(ref workerCount);
4251                }
4252                #endregion
4253
4254                return new ILRetArray<byte>(retStorage);
4255            }
4256        }
4257
4258
4259       
4260        /// <summary>Minimum of A and B elementwise</summary>
4261        /// <param name="A">Input array A</param>
4262        /// <param name="B">Input array B</param>
4263        /// <returns>Array with the minimum elements of A and B</returns>
4264        /// <remarks><para>On empty input an empty array will be returned.</para>
4265        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
4266        /// other array.</para>
4267        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
4268        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
4269        /// can be used to replace the (costly) repmat function for most binary operators.</para>
4270        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
4271        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
4272        public unsafe static ILRetArray<double>  min(ILInArray<double> A, ILInArray<double> B) {
4273            using (ILScope.Enter(A, B)) {
4274                int outLen;
4275                BinOpItMode mode;
4276                double[] retArr;
4277                double[] arrA = A.GetArrayForRead();
4278                double[] arrB = B.GetArrayForRead();
4279                ILSize outDims;
4280                #region determine operation mode
4281                if (A.IsScalar) {
4282                    outDims = B.Size;
4283                    if (B.IsScalar) {
4284                        return array<double>(new double[1] { (A.GetValue(0) > B.GetValue(0)) ? A.GetValue(0) : B.GetValue(0) });
4285                    } else if (B.IsEmpty) {
4286                        return ILRetArray<double>.empty(outDims);
4287                    } else {
4288                        outLen = outDims.NumberOfElements;
4289                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
4290                            retArr = ILMemoryPool.Pool.New< double>(outLen);
4291                            mode = BinOpItMode.SAN;
4292                        } else {
4293                            mode = BinOpItMode.SAI;
4294                        }
4295                    }
4296                } else {
4297                    outDims = A.Size;
4298                    if (B.IsScalar) {
4299                        if (A.IsEmpty) {
4300                            return ILRetArray<double>.empty(A.Size);
4301                        }
4302                        outLen = A.S.NumberOfElements;
4303                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
4304                            retArr = ILMemoryPool.Pool.New<double>(outLen);
4305                            mode = BinOpItMode.ASN;
4306                        } else {
4307                            mode = BinOpItMode.ASI;
4308                        }
4309                    } else {
4310                        // array + array
4311                        if (!A.Size.IsSameSize(B.Size)) {
4312                            return  minEx(A, B);
4313                        }
4314                        outLen = A.S.NumberOfElements;
4315                        if (A.TryGetStorage4InplaceOp(out retArr))
4316                            mode = BinOpItMode.AAIA;
4317                        else if (B.TryGetStorage4InplaceOp(out retArr))
4318                            mode = BinOpItMode.AAIB;
4319                        else {
4320                            retArr = ILMemoryPool.Pool.New<double>(outLen);
4321                            mode = BinOpItMode.AAN;
4322                        }
4323                    }
4324                }
4325                #endregion
4326                ILDenseStorage<double> retStorage = new ILDenseStorage<double>(retArr, outDims);
4327                int i = 0, workerCount = 1;
4328                Action<object> worker = data => {
4329                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
4330                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
4331                   
4332                    double* cp = (double*)range.Item5 + range.Item1;
4333                   
4334                    double scalar;
4335                    int j = range.Item2;
4336                    #region loops
4337                    switch (mode) {
4338                        case BinOpItMode.AAIA:
4339                           
4340                            double* bp = ((double*)range.Item4 + range.Item1);
4341                            while (j > 7) {
4342                                cp[0] = (cp[0]  < bp[0]) ? cp[0] : bp[0];
4343                                cp[1] = (cp[1]  < bp[1]) ? cp[1] : bp[1];
4344                                cp[2] = (cp[2]  < bp[2]) ? cp[2] : bp[2];
4345                                cp[3] = (cp[3]  < bp[3]) ? cp[3] : bp[3];
4346                                cp[4] = (cp[4]  < bp[4]) ? cp[4] : bp[4];
4347                                cp[5] = (cp[5]  < bp[5]) ? cp[5] : bp[5];
4348                                cp[6] = (cp[6]  < bp[6]) ? cp[6] : bp[6];
4349                                cp[7] = (cp[7]  < bp[7]) ? cp[7] : bp[7];
4350                                cp += 8; bp += 8; j -= 8;
4351                            }
4352                            while (j-- > 0) {
4353                                *cp = (*cp  < *bp) ? *cp : *bp;
4354                                cp++; bp++;
4355                            }
4356                            break;
4357                        case BinOpItMode.AAIB:
4358                           
4359                            double* ap = ((double*)range.Item3 + range.Item1);
4360                            while (j > 7) {
4361                                cp[0] = (ap[0]  < cp[0]) ? ap[0] : cp[0];
4362                                cp[1] = (ap[1]  < cp[1]) ? ap[1] : cp[1];
4363                                cp[2] = (ap[2]  < cp[2]) ? ap[2] : cp[2];
4364                                cp[3] = (ap[3]  < cp[3]) ? ap[3] : cp[3];
4365                                cp[4] = (ap[4]  < cp[4]) ? ap[4] : cp[4];
4366                                cp[5] = (ap[5]  < cp[5]) ? ap[5] : cp[5];
4367                                cp[6] = (ap[6]  < cp[6]) ? ap[6] : cp[6];
4368                                cp[7] = (ap[7]  < cp[7]) ? ap[7] : cp[7];
4369                                ap += 8; cp += 8; j -= 8;
4370                            }
4371                            while (j-- > 0) {
4372                                *cp = (*ap  < *cp) ? *ap : *cp;
4373                                ap++; cp++;
4374                            }
4375                            break;
4376                        case BinOpItMode.AAN:
4377                            ap = ((double*)range.Item3 + range.Item1);
4378                            bp = ((double*)range.Item4 + range.Item1);
4379                            while (j > 7) {
4380                                cp[0] = (ap[0]  < bp[0]) ? ap[0] : bp[0];
4381                                cp[1] = (ap[1]  < bp[1]) ? ap[1] : bp[1];
4382                                cp[2] = (ap[2]  < bp[2]) ? ap[2] : bp[2];
4383                                cp[3] = (ap[3]  < bp[3]) ? ap[3] : bp[3];
4384                                cp[4] = (ap[4]  < bp[4]) ? ap[4] : bp[4];
4385                                cp[5] = (ap[5]  < bp[5]) ? ap[5] : bp[5];
4386                                cp[6] = (ap[6]  < bp[6]) ? ap[6] : bp[6];
4387                                cp[7] = (ap[7]  < bp[7]) ? ap[7] : bp[7];
4388                                ap += 8; bp += 8; cp += 8; j -= 8;
4389                            }
4390                            while (j-- > 0) {
4391                                *cp = (*ap  < *bp) ? *ap : *bp;
4392                                ap++; bp++; cp++;
4393                            }
4394                            break;
4395                        case BinOpItMode.ASI:
4396                            scalar = *((double*)range.Item4);
4397                            while (j > 7) {
4398                                cp[0] = (cp[0]  < scalar) ? cp[0] : scalar;
4399                                cp[1] = (cp[1]  < scalar) ? cp[1] : scalar;
4400                                cp[2] = (cp[2]  < scalar) ? cp[2] : scalar;
4401                                cp[3] = (cp[3]  < scalar) ? cp[3] : scalar;
4402                                cp[4] = (cp[4]  < scalar) ? cp[4] : scalar;
4403                                cp[5] = (cp[5]  < scalar) ? cp[5] : scalar;
4404                                cp[6] = (cp[6]  < scalar) ? cp[6] : scalar;
4405                                cp[7] = (cp[7]  < scalar) ? cp[7] : scalar;
4406                                cp += 8; j -= 8;
4407                            }
4408                            while (j-- > 0) {
4409                                *cp = (*cp  < scalar) ? *cp : scalar;
4410                                cp++;
4411                            }
4412                            break;
4413                        case BinOpItMode.ASN:
4414                            ap = ((double*)range.Item3 + range.Item1);
4415                            scalar = *((double*)range.Item4);
4416                            while (j > 7) {
4417                                cp[0] = (ap[0]  < scalar) ? ap[0] : scalar;
4418                                cp[1] = (ap[1]  < scalar) ? ap[1] : scalar;
4419                                cp[2] = (ap[2]  < scalar) ? ap[2] : scalar;
4420                                cp[3] = (ap[3]  < scalar) ? ap[3] : scalar;
4421                                cp[4] = (ap[4]  < scalar) ? ap[4] : scalar;
4422                                cp[5] = (ap[5]  < scalar) ? ap[5] : scalar;
4423                                cp[6] = (ap[6]  < scalar) ? ap[6] : scalar;
4424                                cp[7] = (ap[7]  < scalar) ? ap[7] : scalar;
4425                                ap += 8; cp += 8; j -= 8;
4426                            }
4427                            while (j-- > 0) {
4428                                *cp = (*ap  < scalar) ? *ap : scalar;
4429                                ap++; cp++;
4430                            }
4431                            break;
4432                        case BinOpItMode.SAI:
4433                            scalar = *((double*)range.Item3);
4434                            while (j > 7) {
4435                                cp[0] = (scalar  < cp[0]) ? scalar : cp[0];
4436                                cp[1] = (scalar  < cp[1]) ? scalar : cp[1];
4437                                cp[2] = (scalar  < cp[2]) ? scalar : cp[2];
4438                                cp[3] = (scalar  < cp[3]) ? scalar : cp[3];
4439                                cp[4] = (scalar  < cp[4]) ? scalar : cp[4];
4440                                cp[5] = (scalar  < cp[5]) ? scalar : cp[5];
4441                                cp[6] = (scalar  < cp[6]) ? scalar : cp[6];
4442                                cp[7] = (scalar  < cp[7]) ? scalar : cp[7];
4443                                cp += 8; j -= 8;
4444                            }
4445                            while (j-- > 0) {
4446                                *cp = (scalar  < *cp) ? scalar : *cp;
4447                                cp++;
4448                            }
4449                            break;
4450                        case BinOpItMode.SAN:
4451                            scalar = *((double*)range.Item3);
4452                            bp = ((double*)range.Item4 + range.Item1);
4453                            while (j > 7) {
4454                                cp[0] = (scalar  < bp[0]) ? scalar : bp[0];
4455                                cp[1] = (scalar  < bp[1]) ? scalar : bp[1];
4456                                cp[2] = (scalar  < bp[2]) ? scalar : bp[2];
4457                                cp[3] = (scalar  < bp[3]) ? scalar : bp[3];
4458                                cp[4] = (scalar  < bp[4]) ? scalar : bp[4];
4459                                cp[5] = (scalar  < bp[5]) ? scalar : bp[5];
4460                                cp[6] = (scalar  < bp[6]) ? scalar : bp[6];
4461                                cp[7] = (scalar  < bp[7]) ? scalar : bp[7];
4462                                bp += 8; cp += 8; j -= 8;
4463                            }
4464                            while (j-- > 0) {
4465                                *cp = (scalar  < *bp) ? scalar : *bp;
4466                                bp++; cp++;
4467                            }
4468                            break;
4469                        default:
4470                            break;
4471                    }
4472                    #endregion
4473                    System.Threading.Interlocked.Decrement(ref workerCount);
4474                    //retStorage.PendingEvents.Signal();
4475                };
4476
4477                #region do the work
4478                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
4479                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
4480                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
4481                        workItemLength = outLen / workItemCount;
4482                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
4483                    } else {
4484                        workItemLength = outLen / 2;
4485                        workItemCount = 2;
4486                    }
4487                } else {
4488                    workItemLength = outLen;
4489                    workItemCount = 1;
4490                }
4491
4492                fixed (double* arrAP = arrA)
4493                fixed (double* arrBP = arrB)
4494                fixed (double* retArrP = retArr) {
4495
4496                    for (; i < workItemCount - 1; i++) {
4497                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
4498                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
4499                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
4500                        System.Threading.Interlocked.Increment(ref workerCount);
4501                        ILThreadPool.QueueUserWorkItem(i, worker, range);
4502                    }
4503                    // the last (or may the only) chunk is done right here
4504                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
4505                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
4506                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
4507
4508                    ILThreadPool.Wait4Workers(ref workerCount);
4509                }
4510
4511                #endregion
4512                return new ILRetArray<double>(retStorage);
4513            }
4514        }
4515
4516        private static unsafe ILRetArray<double>  minEx(ILInArray<double> A, ILInArray<double> B) {
4517            using (ILScope.Enter(A, B)) {
4518
4519                #region parameter checking
4520                if (isnull(A) || isnull(B))
4521                    return empty<double>(ILSize.Empty00);
4522                if (A.IsEmpty) {
4523                    return empty<double>(B.S);
4524                } else if (B.IsEmpty) {
4525                    return empty<double>(A.S);
4526                }
4527                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
4528                //    return add(A,B);
4529                int dim = -1;
4530                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
4531                    if (A.S[l] != B.S[l]) {
4532                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
4533                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
4534                        }
4535                        dim = l;
4536                    }
4537                }
4538                if (dim > 1)
4539                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
4540                #endregion
4541
4542                #region parameter preparation
4543
4544               
4545                double[] retArr;
4546
4547               
4548                double[] arrA = A.GetArrayForRead();
4549
4550               
4551                double[] arrB = B.GetArrayForRead();
4552                ILSize outDims;
4553                BinOptItExMode mode;
4554                int arrInc = 0;
4555                int arrStepInc = 0;
4556                int dimLen = 0;
4557                if (A.IsVector) {
4558                    outDims = B.S;
4559                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
4560                        retArr = ILMemoryPool.Pool.New<double>(outDims.NumberOfElements);
4561                        mode = BinOptItExMode.VAN;
4562                    } else {
4563                        mode = BinOptItExMode.VAI;
4564                    }
4565                    dimLen = A.Length;
4566                } else if (B.IsVector) {
4567                    outDims = A.S;
4568                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
4569                        retArr = ILMemoryPool.Pool.New<double>(outDims.NumberOfElements);
4570                        mode = BinOptItExMode.AVN;
4571                    } else {
4572                        mode = BinOptItExMode.AVI;
4573                    }
4574                    dimLen = B.Length;
4575                } else {
4576                    throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
4577                }
4578                arrInc = (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
4579                arrStepInc = outDims.SequentialIndexDistance(dim);
4580                #endregion
4581
4582                #region worker loops definition
4583                ILDenseStorage<double> retStorage = new ILDenseStorage<double>(retArr, outDims);
4584                int workerCount = 1;
4585                Action<object> worker = data => {
4586                    // expects: iStart, iLen, ap, bp, cp
4587                    Tuple<int, int, IntPtr, IntPtr, IntPtr> range =
4588                        (Tuple<int, int, IntPtr, IntPtr, IntPtr>)data;
4589
4590                   
4591                    double* ap;
4592
4593                   
4594                    double* bp;
4595
4596                   
4597                    double* cp;
4598                    switch (mode) {
4599                        case BinOptItExMode.VAN:
4600                            for (int s = 0; s < range.Item2; s++) {
4601                                ap = (double*)range.Item3;
4602                                bp = (double*)range.Item4 + range.Item1 + s * arrStepInc; ;
4603                                cp = (double*)range.Item5 + range.Item1 + s * arrStepInc;
4604                                for (int l = 0; l < dimLen; l++) {
4605                                    *cp = (*ap  < *bp) ? *ap : *bp;
4606                                    ap++;
4607                                    bp += arrInc;
4608                                    cp += arrInc;
4609                                }
4610                            }
4611                            break;
4612                        case BinOptItExMode.VAI:
4613                            for (int s = 0; s < range.Item2; s++) {
4614                                ap = (double*)range.Item3;
4615                                cp = (double*)range.Item5 + range.Item1 + s * arrStepInc;
4616                                for (int l = 0; l < dimLen; l++) {
4617                                    *cp = (*ap  < *cp) ? *ap : *cp;
4618                                    ap++;
4619                                    cp += arrInc;
4620                                }
4621                            }
4622                            break;
4623                        case BinOptItExMode.AVN:
4624                            for (int s = 0; s < range.Item2; s++) {
4625                                ap = (double*)range.Item3 + range.Item1 + s * arrStepInc;
4626                                bp = (double*)range.Item4;
4627                                cp = (double*)range.Item5 + range.Item1 + s * arrStepInc;
4628                                for (int l = 0; l < dimLen; l++) {
4629                                    *cp = (*ap  < *bp) ? *ap : *bp;
4630                                    ap += arrInc;
4631                                    bp++;
4632                                    cp += arrInc;
4633                                }
4634                            }
4635                            break;
4636                        case BinOptItExMode.AVI:
4637                            for (int s = 0; s < range.Item2; s++) {
4638                                bp = (double*)range.Item4;
4639                                cp = (double*)range.Item5 + range.Item1 + s * arrStepInc;
4640                                for (int l = 0; l < dimLen; l++) {
4641                                    *cp = (*cp  < *bp) ? *cp : *bp;
4642                                    bp++;
4643                                    cp += arrInc;
4644                                }
4645                            }
4646                            break;
4647                    }
4648                    System.Threading.Interlocked.Decrement(ref workerCount);
4649                };
4650                #endregion
4651
4652                #region work distribution
4653                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
4654                int outLen = outDims.NumberOfElements;
4655                if (Settings.s_maxNumberThreads > 1 && outLen / 2 >= Settings.s_minParallelElement1Count) {
4656                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
4657                        workItemLength = outLen / dimLen / workItemCount;
4658                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
4659                    } else {
4660                        workItemLength = outLen / dimLen / 2;
4661                        workItemCount = 2;
4662                    }
4663                } else {
4664                    workItemLength = outLen / dimLen;
4665                    workItemCount = 1;
4666                }
4667
4668                fixed (double* arrAP = arrA)
4669                fixed (double* arrBP = arrB)
4670                fixed (double* retArrP = retArr) {
4671
4672                    for (; i < workItemCount - 1; i++) {
4673                        Tuple<int, int, IntPtr, IntPtr, IntPtr> range
4674                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr>
4675                               (i * workItemLength * arrStepInc, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP);
4676                        System.Threading.Interlocked.Increment(ref workerCount);
4677                        ILThreadPool.QueueUserWorkItem(i, worker, range);
4678                    }
4679                    // the last (or may the only) chunk is done right here
4680                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
4681                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr>
4682                                (i * workItemLength * arrStepInc, (outLen / dimLen) - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP));
4683
4684                    ILThreadPool.Wait4Workers(ref workerCount);
4685                }
4686                #endregion
4687
4688                return new ILRetArray<double>(retStorage);
4689            }
4690        }
4691
4692
4693
4694#endregion HYCALPER AUTO GENERATED CODE
4695
4696    }
4697}
Note: See TracBrowser for help on using the repository browser.