Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Misc/ILSize.cs @ 11310

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

#1967: ILNumerics source for experimentation

File size: 32.6 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 ILNumerics.Storage;     
42using ILNumerics.Exceptions;
43using System.Collections.Generic;
44
45namespace ILNumerics
46{
47    /// <summary>
48    /// ILSize - dimensions for array objects (immutable)
49    /// </summary>
50    /// <remarks>The class internally manages the dimensions of ILNumerics arrays.
51    /// The class is immutable. Therefore, once created, it informs the user
52    /// about all dimension related properties, but cannot get altered.</remarks>
53    [Serializable]
54    [System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
55    public class ILSize {
56       
57        #region attributes
58        internal int [] m_dims;
59        int m_nrDims = 0;
60        int m_numberOfElements = 0;
61        int m_length = 0;
62        int [] m_seqDistancesCache;
63        static ILSize s_emptyDimension = new ILSize(0,0);
64        static ILSize s_scalarDimension = new ILSize(1,1);
65        static ILSize s_twoElementDim = new ILSize(2,1);
66        static ILSize s_threeElementDim = new ILSize(3,1);
67       
68        [ThreadStatic]
69        static List<int> s_listCache;
70        static List<int> ListCache {
71            get {
72                List<int> ret = s_listCache;
73                if (ret == null) {
74                    s_listCache = new List<int>();
75                    ret = s_listCache;
76                }
77                return ret;
78            }
79        }
80        #endregion
81
82        #region constructors
83        /// <summary>
84        /// Create new ILSize
85        /// </summary>
86        /// <param name="dims">variable length dimensions specifier</param>
87        /// <remarks>Trailing singleton dimensions of dims will be kept.</remarks>
88        public ILSize(params int[] dims) {
89            if (dims == null)
90                throw new ILArgumentException("invalid dimension specification. the number of dimensions must not be 0.");
91            int outLen = Math.Max(2, dims.Length);
92            m_dims = new int[outLen];
93            for (int i = 0; i < dims.Length; i++) {
94                m_dims[i] = dims[i];
95            }
96            for (int i = dims.Length; i < 2; i++) {
97                m_dims[i] = 1;
98            }
99            m_numberOfElements = 1;
100            m_nrDims = m_dims.Length;
101            int t = 0,
102                d;
103            for (; t < m_dims.Length; t++) {
104                d = m_dims[t];
105                if (d > m_length) m_length = d;
106                m_numberOfElements *= d;
107            }
108        }
109
110        /// <summary>
111        /// Create new size descriptor from given data
112        /// </summary>
113        /// <param name="size">Size description</param>
114        public ILSize(params ILBaseArray[] size)
115            : this (convert2int(size)) {
116
117        }
118
119        /// <summary>
120        /// Create new size descriptor
121        /// </summary>
122        /// <param name="trimSingletons">true: trailing singleton
123        /// dimensions will be trimmed, false: keep trailing singleton dimensions</param>
124        /// <param name="size">Size description</param>
125        public ILSize (bool trimSingletons, params int[] size)  {
126            if (!trimSingletons) {
127                if (size == null)
128                    throw new ILArgumentException("invalid size specification. the number of dimensions must not be 0.");
129                int outLen = Math.Max(2, size.Length);
130                m_dims = new int[outLen];
131                for (int i = 0; i < size.Length; i++) {
132                    m_dims[i] = size[i];
133                }
134                for (int i = size.Length; i < 2; i++) {
135                    m_dims[i] = 1;
136                }
137                m_numberOfElements = 1;
138                m_nrDims = m_dims.Length;
139                int t = 0,
140                    d;
141                for (; t < m_dims.Length; t++) {
142                    d = m_dims[t];
143                    if (d > m_length) m_length = d;
144                    m_numberOfElements *= d;
145                }
146            } else {
147                ListCache.Clear();
148                s_listCache.AddRange(size);
149                while (s_listCache.Count < 2)
150                    s_listCache.Add(1);
151                if (trimSingletons)
152                    for (int i = s_listCache.Count; i-- > 2; ) {
153                        if (s_listCache[i] == 1) s_listCache.RemoveAt(i);
154                        else break;
155                    }
156                m_dims = s_listCache.ToArray();
157                m_numberOfElements = 1;
158                m_nrDims = m_dims.Length;
159                int t = 0,
160                    d;
161                for (; t < m_dims.Length; t++) {
162                    d = m_dims[t];
163                    if (d > m_length) m_length = d;
164                    m_numberOfElements *= d;
165                }
166            }
167        }
168
169        /// <summary>
170        /// An size descriptor of size 0x0
171        /// </summary>
172        public static ILSize Empty00 {
173            get {
174                return s_emptyDimension; }
175        }
176        /// <summary>
177        /// An size descriptor of size 1x1
178        /// </summary>
179        public static ILSize Scalar1_1
180        {
181            get {
182                return s_scalarDimension; }
183        }
184        /// <summary>
185        /// An size descriptor of size 2x1
186        /// </summary>
187
188        public static ILSize Column2_1 {
189            get {
190                return s_twoElementDim; }
191        }
192        /// <summary>
193        /// An size descriptor of size 3x1
194        /// </summary>
195        public static ILSize Column3_1 {
196            get {
197                return s_threeElementDim; }
198        }
199        #endregion
200
201        #region properties
202        /// <summary>Get number of dimensions.</summary>
203        public int NumberOfDimensions {
204            get {
205                return m_nrDims;
206            }
207        }
208
209        /// <summary>
210        /// Number of non singleton dimensions of the array
211        /// </summary>
212        /// <remarks>Non singleton dimensions are dimensions which length is larger than 1.
213        /// Empty dimensions (length = 0) will not be taken into account.</remarks>
214        public int NonSingletonDimensions {
215            // ToDo: Definition of non-singelton (= not 1) should be reconsidered. Here 0 is not counted as non-singelton
216            get {
217                int ret = 0;
218                for (int i = 0; i < m_nrDims; i++) {
219                    if (m_dims[i] > 1) ret++;
220                }
221                return ret;
222            }
223        }
224        /// <summary>
225        /// Number of elements in the array
226        /// </summary>
227        public int NumberOfElements {
228            get {
229                return m_numberOfElements;
230            }
231        }
232        /// <summary>
233        /// Length of the longest dimension
234        /// </summary>
235        public int Longest {
236            get {
237                return m_length;
238            }
239        }
240        /// <summary>
241        /// Find dimension to work on, if non was specified by user
242        /// </summary>
243        /// <returns>Index of first non singleton dimension (i.e. dimension that is not 1) or 0, if this array is a scalar.</returns>
244        internal int WorkingDimension() {
245            // if (m_numberOfElements <= 1) return -1;
246            for (int i = 0; i < m_nrDims; i++) {
247                if (m_dims[i] != 1) return i;
248            }
249            // return -1; // this should not happen! Test on scalar above
250            return 0; // All dimensions are 1, return first one
251        }
252        #endregion
253
254        #region public member
255        /// <summary>
256        /// Storage distance of elements in dimension dim
257        /// </summary>
258        /// <param name="dim">0-based index of dimension to query the element distance for</param>
259        /// <returns>Storage distance of elements between adjacent elements of dimension dim
260        /// </returns>
261        /// <remarks>If dimension index dim is larger than the number of
262        /// dimensions of this array, the number of elements will
263        /// be returned (trailing singleton dimensions).</remarks>
264        public int SequentialIndexDistance(int dim) {
265            if (dim >= m_nrDims)
266                return m_numberOfElements;
267            dim %= m_nrDims;
268            int ret = 1;
269            for (int i = 0; i < dim && i < m_nrDims; i++) {
270                ret *= m_dims[i];
271            }
272            return ret;
273        }
274        /// <summary>
275        /// Distances between adjacent elements for all dimensions
276        /// </summary>
277        /// <param name="minLength">minimum length of array to be
278        /// returned. If this is larger than the number of dimensions
279        /// in this size descriptor, the array will have minLength elements,
280        /// with elements outside this dimensions repeating the value
281        /// of the last dimension. The length of the array returned will
282        /// be equal or greater than max(minLength,NumberOfDimensions).</param>
283        /// <remarks>This is provided for performance reasons and should be
284        /// used internally only. It enables developer of index access routines
285        /// to cache the elements distances directly inside their functions
286        /// without having to query the info on every index access.
287        /// <para>Keep in mind, only the distances for the number of my
288        /// dimensions are returned. Higher dimensions must be set to
289        /// NumberOfElements if needed. This is different than querying
290        /// the distances by SequentialIndexDistance(int), which will assume
291        /// and return trailing dimensions to be 1.</para>
292        /// <para>IMPORTANT: ALTERING THE ARRAY RETURNED IS NOT ALLOWED AND
293        /// MAY LEAD TO SERIOUS INSTABILITY AND UNWANTED SIDE EFFECTS!</para></remarks>
294        internal int[] GetSequentialIndexDistances(int minLength) {
295            minLength = Math.Max(m_nrDims,minLength);
296            if (m_seqDistancesCache == null || m_seqDistancesCache.Length < minLength){
297                m_seqDistancesCache = new int[minLength];
298                int tmp = 1, i = 0;
299                for (; i < m_nrDims; i++) {
300                    m_seqDistancesCache[i] = tmp;
301                    tmp *= m_dims[i];
302                }
303                for (; i < m_seqDistancesCache.Length; i++) {
304                    m_seqDistancesCache[i] = tmp;
305                }
306            }
307            return m_seqDistancesCache;
308        }
309        /// <summary>
310        /// Transfer my dimensions to integer array
311        /// </summary>
312        /// <returns>Integer array containing a copy of all dimensions length</returns>
313        public int[] ToIntArray(){
314            return (int[])m_dims.Clone();
315        }
316        /// <summary>
317        /// Transfer my dimensions to integer array
318        /// </summary>
319        /// <param name="length">Minimum length of output array. If length
320        /// is larger than my dimensions, trailing ones will be added.</param>
321        /// <returns>Integer array containing a copy of dimensions length.
322        /// Trailing elements outside my dims will be one.</returns>
323        internal int[] ToIntArray (int length) {
324            int[] ret;
325            ret = new int[length > m_nrDims ? length : m_nrDims];
326            Array.Copy(m_dims,0,ret,0,m_nrDims);
327            for (int i = m_nrDims; i < length; i++) {
328                ret[i] = 1;
329            }
330            return ret;
331        }
332        /// <summary>
333        /// return dimension vector, fixed length, for subarray operations
334        /// </summary>
335        /// <param name="length"></param>
336        /// <returns>dimension vector, corresponds to reshaped or unlimited dimensions</returns>
337        internal int[] ToIntArrayEx (int length) {
338            int[] ret;
339            if (length == m_nrDims) {
340                ret = new int[length];
341                Array.Copy(m_dims,0,ret,0,m_nrDims);
342            } else if (length > m_nrDims) {
343                ret = new int[length];
344                int i = 0;
345                for (; i < m_dims.Length; i++) {
346                    ret[i] = m_dims[i];
347                }
348                for (; i < length; i++) {
349                    ret[i] = 1;
350                }
351            } else if (length > 0) {
352                ret = new int[length];
353                int i = 0;
354                for (; i < length; i++) {
355                    ret[i] = m_dims[i];
356                }
357                for (int a = i--; a < m_dims.Length; a++) {
358                    ret[i] *= m_dims[a];
359                }
360            } else
361                throw new ILArgumentException("the length parameter must be positive");
362            return ret;
363        }
364        /// <summary>
365        /// Transform indices from int[] System.Array into sequential index of underlying 1dim array
366        /// </summary>
367        /// <param name="idx">int array of nrDims length, min length: 1, all indices must fit into my dimensions</param>
368        /// <returns>Index pointing to element defined by 'idx'</returns>
369        public int IndexFromArray(int[] idx) {     
370            int ret = idx[0];
371            if (ret < 0 || ret >= m_dims[0])
372                throw new ILArgumentException("index out of bounds, dimension # 0");
373            int i = 1, tmp, len = (idx.Length < m_nrDims) ? idx.Length : m_nrDims;
374            for (; i < len-1; i++) {
375                tmp = idx[i];
376                if (tmp >= m_dims[i] || tmp < 0)
377                    throw new ILArgumentException("index out of bounds, dimension # " + i);
378                ret += tmp * SequentialIndexDistance(i);
379            }
380            if (i < len) {
381                tmp = idx[i];
382                if (tmp < 0 || tmp >= m_dims[i]) throw new ILArgumentException("index out of bounds, dimension # " + i);
383                ret += tmp * SequentialIndexDistance(i);
384            }
385            return ret;
386        }
387        /// <summary>
388        /// Transform dimension position into sequential index, gather expand
389        /// information
390        /// </summary>
391        /// <param name="idx">int array of arbitrary length</param>
392        /// <param name="MustExpand">[output] true, if the indices
393        /// given address an element outside of
394        /// this dimensions size. In this case, the output parameter
395        /// 'Dimensions' carry the sizes
396        /// of new dimensions needed. False otherwise</param>
397        /// <param name="dimensions">sizes of dimension if expansion is needed.
398        /// Must be predefined to length of max(idx.Length,m_nrDims) at least</param>
399        /// <returns>Index number pointing to the value's position in
400        /// sequential storage.</returns>
401        /// <remarks>no checks are made for idx to fit inside dimensions!
402        /// This functions is used for left side assignments. Therefore it
403        /// computes the destination index also if it lays outside
404        /// the array bounds.</remarks>
405        internal int IndexFromArray(ref bool MustExpand, ref int[] dimensions, int[] idx) {
406            int tmp;
407            if (idx.Length < m_nrDims) {
408                #region idx < nrDims
409                // expanding is allowed for all but the last specified dimension
410                // reason: if less than m_nrDims idx entries exist, the array is
411                // reshaped to that number of dimensions and the index access
412                // computed according to the reshaped version. Attempts to expand
413                // that last (virtual) dimension is not allowed than since that
414                // dimension would be ambigous.
415                #region special case: sequential addressing
416                if (idx.Length < 2) {
417                    if (idx.Length == 1) {
418                        tmp = idx[0];
419                        if (tmp >= m_numberOfElements) {
420                            // allowed only for scalars and vectors
421                            if (m_dims[0] == m_numberOfElements) {
422                                dimensions[0] = tmp+1;
423                                MustExpand = true;
424                                return tmp;
425                            } else if (m_dims[1] == m_numberOfElements) {
426                                dimensions[1] = tmp+1;
427                                MustExpand = true;
428                                return tmp;
429                            } else
430                                throw new ILArgumentException("invalid attempt to expand non vector sized array");
431                        } else {
432                            return tmp;
433                        }
434                    }
435                    throw new ILArgumentException("invalid index specification: must not be empty");
436                }
437                #endregion
438                int d = 0, faktor = 1;
439                int ret = 0;
440                tmp = idx[0];
441                while (d < idx.Length-1) {
442                    if (tmp < 0)
443                        throw new ILArgumentException("check index at dimension #" + d.ToString() + "!");
444                    if (tmp >= m_dims[d]) {
445                        dimensions[d] = tmp+1;
446                        MustExpand = true;
447                        ret += (faktor * tmp);
448                        faktor *= tmp+1;
449                    } else {
450                        ret += (faktor * tmp);
451                        faktor *= m_dims[d];
452                    }
453                    tmp = idx[++d];
454                }
455                while (d < m_nrDims) {
456                    ret += faktor * ((tmp % m_dims[d]));
457                    tmp /= m_dims[d];
458                    faktor *= m_dims[d++];
459                }
460                if (tmp > 0)
461                    throw new ILArgumentException("expanding is allowed for explicitly bounded dimensions only! You must specify indices into all existing dimensions.");
462                return ret;
463                #endregion
464            } else if (idx.Length == m_nrDims) {
465                // expanding is allowed for all dimensions
466                int d = 0,faktor = 1;
467                int ret = 0;
468                while (d < idx.Length) {
469                    tmp = idx[d];
470                    if (tmp < 0)
471                        throw new ILArgumentException("check index at dimension #" + d.ToString() + " !");
472                    if (tmp >= m_dims[d]) {
473                        dimensions[d] = tmp+1;
474                        MustExpand = true;
475                        ret += (faktor * tmp);
476                        faktor *= tmp+1;
477                    } else {
478                        ret += (faktor * tmp);
479                        faktor *= m_dims[d];
480                    }
481                    d++;
482                }
483                return ret;
484            } else {
485                // idx dimensions are larger than my dimensions
486                int d = 0, faktor = 1;
487                int ret = 0;
488                tmp = idx[0];
489                while (d < m_nrDims) {
490                    tmp = idx[d];
491                    if (tmp < 0)
492                        throw new ILArgumentException("check index at dimension " + d.ToString() + "!");
493                    if (tmp >= m_dims[d]) {
494                        dimensions[d] = tmp+1;
495                        MustExpand = true;
496                        ret += (faktor * tmp);
497                        faktor *= tmp+1;
498                   } else {
499                        ret += (faktor * tmp);
500                        faktor *= m_dims[d];
501                    }
502                    d++;
503                }
504                while (d < idx.Length) {
505                    tmp = idx[d];
506                    if (tmp > 0) {
507                        dimensions[d] = tmp +1;
508                        MustExpand = true;
509                    }
510                    d++;
511                    faktor *= tmp;
512                    ret += faktor;
513                }
514                return ret;
515            }
516        }
517        /// <summary>
518        /// Unshift dimensions of indices from int[] Array
519        /// and translate to index for sequential storage access
520        /// in my dimensions </summary>
521        /// <param name="idx">int array of the same length as
522        /// the number of dimensions of this storage. Indices must
523        /// lay within my dimensions.</param>
524        /// <param name="unshift">Number of dimensions to unshift
525        /// idx before computing index</param>
526        /// <returns>Index number pointing to the value's position
527        /// in sequential storage.</returns>
528        /// <remarks>If idx contains elements (indices) larger than
529        /// my dimension bounds, an exception will be thrown. If unshift
530        /// is 0, the length of idx may be smaller than the length of
531        /// my dimensions. However, with unshift &gt; 0 the result
532        /// is undefined.</remarks>
533        public int IndexFromArray(int[] idx, int unshift) {
534            unshift %= m_nrDims;
535            int faktor = m_dims[0];
536            int ret = idx[(-unshift) % m_nrDims];
537            int d = 1;
538            for (; d<idx.Length; d++) {
539                ret += idx[(-unshift + d) % m_nrDims] * faktor;
540                faktor *= m_dims[d];
541            }
542            return ret;       
543        }
544        /// <summary>
545        /// Return shifted version
546        /// </summary>
547        /// <param name="shift">Number of dimensions to shift. The value
548        /// will be considered modules the number of dimensions of
549        /// this size descriptor.</param>
550        /// <returns>Shifted version of this size descriptor object.</returns>
551        public ILSize GetShifted(int shift){
552            shift %= m_nrDims;
553            if (shift < 0) shift += m_nrDims;
554            int [] tmp = new int [m_nrDims];
555            int id;
556            for (int d = 0; d < m_nrDims; d++) {
557                id = (d + shift) % m_nrDims;
558                tmp[d] = m_dims[id];
559            }
560            return new ILSize(tmp);
561        }
562        /// <summary>
563        /// Create dimension sizes for reshaping index adressing
564        /// </summary>
565        /// <param name="dimCount">Needed number of destination array dimensions</param>
566        /// <returns>Dimension sizes, cutted trailing dimensions are multiplied to last dimension returned.</returns>
567        public int[] GetReshapedSize(int dimCount) {
568            dimCount = Math.Max(1,dimCount);
569            if (dimCount >= m_nrDims) {
570                return ToIntArray(dimCount);
571            }
572            int[] ret = new int[Math.Max(dimCount,2)];
573            for (int i = 0; i < dimCount; i++) {
574                ret[i] = m_dims[i];
575            }
576            for (int i = dimCount; i < m_nrDims; i++) {
577                ret[dimCount - 1] *= m_dims[i];
578            }
579            if (dimCount < 2)
580                ret[1] = 1;
581            return ret;
582        }
583        /// <summary>
584        /// Get length for dimension specified (Readonly)
585        /// </summary>
586        /// <param name="idx">Index of dimension</param>
587        /// <returns>Length of dimension specified by idx</returns>
588        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If idx is negative</exception>
589        /// <remarks><para>For idx corresponds to an existing dimension,
590        /// the length of that dimension is returned. If idx is larger than
591        /// the number of dimensions 1 is returned. </para>
592        /// </remarks>
593        public int this [int idx] {
594            get {
595                if (idx < 0)
596                    throw new ArgumentOutOfRangeException("index","Index out of Range!");
597                else if (idx >= m_nrDims) {
598                    return 1;
599                }
600                return m_dims[idx];
601            }
602        }
603        /// <summary>
604        /// Compares the size of this dimension to another dimension object.
605        /// </summary>
606        /// <param name="dim2">size descriptor to compare this to.</param>
607        /// <returns>Returns true if the sizes are the same, else returns false.
608        /// The comparison is made by recognizing singleton dimensions. Therefore
609        /// only non singleton dimensions are compared in the order of their
610        /// appearance. </returns>
611        /// <remarks>The function returns true, if the squeezed dimensions of
612        /// both size descriptors match.</remarks>
613        public bool IsSameSize(ILSize dim2) {
614            if (dim2.NumberOfElements != m_numberOfElements) return false;
615            for (int d2 = dim2.NumberOfDimensions,d1 = m_nrDims;d1 >= 0;) {
616                d1--; d2--;
617                while (d1 >= 0 && m_dims[d1]== 1) d1--;
618                while (d2 >= 0 && dim2[d2]  == 1) d2--;
619                if (d1 >= 0 && d2 >= 0) {
620                    if (m_dims[d1] != dim2[d2])
621                        return false;
622
623                }
624            }
625            return true;
626        }
627        /// <summary>
628        /// Compares the shape of this dimension to another dimension object
629        /// </summary>
630        /// <param name="dim2">size descriptor to compare this to.</param>
631        /// <returns>Returns true if the shapes are the same, else returns false. </returns>
632        /// <remarks>This function is more strict than IsSameSize. In order
633        /// for two dimensions to have the same shape, ALL dimensions must match -
634        /// even singleton dimensions.</remarks>
635        public bool IsSameShape(ILSize dim2) {
636            if (dim2.NumberOfElements != m_numberOfElements) return false;
637            if (dim2.NumberOfDimensions != m_nrDims) return false;
638            for (int d1 = m_nrDims;d1-->0;) {
639                if (m_dims[d1] != dim2.m_dims[d1])
640                    return false;
641            }
642            return true;
643        }
644        /// <summary>
645        /// [deprecated] Create copy of this size descriptor having all singleton
646        /// dimensions removed.
647        /// </summary>
648        /// <returns>a squeezed copy</returns>
649        /// <remarks>This function is deprecated. Use the ILSize.Squeeze()
650        /// memeber instead. </remarks>
651        [Obsolete("Use the ILSize.Squeeze() instead")]
652        public ILSize GetSqueezed() {
653            return Squeeze();
654        }
655        /// <summary>
656        /// Create and return copy without singleton dimensions
657        /// </summary>
658        /// <returns>Copy of this size descriptor having all singleton dimensions removed.</returns>
659        /// <remarks> This function does not alter this object (since ILSize is
660        /// immutable).
661        /// <para>All arrays in ILNumerics have at least 2 dimensions.
662        /// Therefore all but the first two singleton dimensions can be removed.</para>
663        /// </remarks>
664        public ILSize Squeeze() {
665            List<int> tmp = new List<int>();
666            foreach (int d in m_dims) {
667                if (d != 1) tmp.Add(d);
668            }
669            while (tmp.Count < 2) {
670                tmp.Add(1);
671            }
672            return new ILSize(tmp.ToArray());
673        }
674        /// <summary>
675        /// Return size descriptor, having trailing singleton dimensions removed
676        /// </summary>
677        /// <returns>Copy without trailing singleton dimensions</returns>
678        /// <remarks>This object will NOT be altered. As usual for all ILArrays,
679        /// the result wil have at least 2 dimensions.</remarks>
680        public ILSize Trim() {
681            if (m_nrDims == 2 || m_dims[m_nrDims-1] != 1) {
682                return this;
683            }
684            int i = m_nrDims;
685            for (; i-->2; ) if (m_dims[i] != 1) break;
686            int[] newdims = new int[++i];
687            System.Array.Copy(m_dims,0,newdims,0,i);
688            return new ILSize(newdims);
689        }
690
691        /// <summary>
692        /// Pretty print dimensions in the format "[a,b,c]"
693        /// </summary>
694        /// <returns>Dimensions as String</returns>
695        public override String ToString (){
696            String s = "[";
697            for (int t = 0; t < m_nrDims; t++) {
698                s = s + m_dims[t];
699                if (t < m_nrDims -1 )
700                    s = s + ",";
701            }
702            s = s + "]";
703            return s;
704        }
705        /// <summary>
706        /// Generate hash code based on the dimension information
707        /// </summary>
708        /// <returns>Hash code</returns>
709        public override int GetHashCode() {
710            int ret = m_dims.Length;
711            foreach (int i in m_dims) {
712                ret = ret * 17 + i;
713            }
714            return ret;
715        }
716        /// <summary>
717        /// Checks for equaltiy of this dimensions to another dimensions object
718        /// </summary>
719        /// <param name="obj">Dimensions object to compare this instance with</param>
720        /// <returns>true, if both dimensions have the same <b>shape</b></returns>
721        /// <remarks>This is equivalent to <c>IsSameShape((ILSize)obj)</c>.</remarks>
722        public override bool Equals(object obj) {
723            if (object.ReferenceEquals(obj, null)) return false;
724            ILSize objDim = obj as ILSize;
725            if (objDim != null) {
726                return IsSameShape(objDim);
727            } else {
728                return false;
729            }
730
731        }
732        #endregion
733
734        #region private helpers
735        private static int[] convert2int(ILBaseArray[] dimensions) {
736            using (ILScope.Enter(dimensions)) {
737                if (dimensions == null || dimensions.Length == 0) {
738                    return new int[2];
739                }
740                int[] ret = new int[dimensions.Length];
741                if (dimensions.Length > 1) {
742                    for (int i = 0; i < ret.Length; i++) {
743                        ILBaseArray A = dimensions[i];
744                        if (object.Equals(A, null) || !A.IsScalar || !A.IsNumeric) {
745                            throw new ILArgumentException("dimension specifier must be numeric scalars");
746                        }
747                        ret[i] = (int)ILMath.todouble(A).GetValue(0);
748                    }
749                } else {
750                    // if exactly one array was given, it must be a numeric int vector with the dim specification
751                    ILBaseArray A = dimensions[0];
752                    if (object.Equals(A, null) || !A.IsVector || !A.IsNumeric) {
753                        throw new ILArgumentException("invalid dimension specification");
754                    }
755                    ILArray<int> Aint = ILMath.toint32(A);
756                    Aint.ExportValues(ref ret); 
757                }
758                return ret;
759            }
760        }
761        #endregion
762
763    }
764}
Note: See TracBrowser for help on using the repository browser.