/// /// This file is part of ILNumerics Community Edition. /// /// ILNumerics Community Edition - high performance computing for applications. /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net /// /// ILNumerics Community Edition is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License version 3 as published by /// the Free Software Foundation. /// /// ILNumerics Community Edition is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /// GNU General Public License for more details. /// /// You should have received a copy of the GNU General Public License /// along with ILNumerics Community Edition. See the file License.txt in the root /// of your distribution package. If not, see . /// /// In addition this software uses the following components and/or licenses: /// /// ================================================================================= /// The Open Toolkit Library License /// /// Copyright (c) 2006 - 2009 the Open Toolkit library. /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights to /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software is furnished to do /// so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in all /// copies or substantial portions of the Software. /// /// ================================================================================= /// using System; using ILNumerics; using ILNumerics.Misc; using ILNumerics.Exceptions; using ILNumerics.Data; using System.Collections.Generic; using System.Linq.Expressions; namespace ILNumerics.Storage { /// /// base class for ranges, used to define subarray ranges /// /// ILRange is used to define those parts of indices of an array, /// which are to be extracted into a new subarray. /// The class (and derived classes) parse indices given for each dimension and expand them into a 2-dimensional /// integer array, needed for fast element traversal. /// The class is internally used only and not intended to be used from outside ILNumerics. internal abstract class ILRange : IDisposable { /// /// hold ranges as 2 dimensional System.Array /// protected ILIntList[] m_range; /// /// for performance reasons: give reference to internal array /// internal ILIntList[] RangeArray { get{ return m_range; } } /// /// Index access for ILRange objects. Set/returns Index array for specified dimension. /// /// A reference to the internal object will be returned directly! (performance) internal ILIntList this [int idx] { get { return m_range[idx]; } } /// /// Index access for ILRange objects. returns the destIndex destination dimension for dimension specifyied by dimNr. /// /// The access is readonly! No checks are made, if the requested indices exist. internal int this [int dimNr,int destIndx ] { get { return m_range[dimNr][destIndx]; } } internal void ILRanges() {} /// /// Evaluates (maps) index array on my range. /// /// int array indexing location inside this range /// (output) also return the result into array given /// Mapped int[] array. It can be used for direct addressing the physical storage object. /// retIdx must be at least of length m_nrDims. No check is made for this assumption! internal int[] Map(int[] idx, ref int [] retIdx) { int tmpVal; for (int d = 0; d < m_size.NumberOfDimensions; d++) { tmpVal = m_range[d][0]; if (tmpVal < 0) retIdx[d] = idx[d]; else retIdx[d] = m_range[d][idx[d]]; } return retIdx; } /// /// parse single dimension specifier from string /// /// valid index specification /// number of elements in dimension to be parsed /// array with indices defined in 'indices' /// the indices are parsed the way needed for sequential addressing. This means: /// full dimensions address the whole array. Full dimensions are transformed into negative /// placeholder indices nevertheless! SetRange must handle that accordingly. internal static ILBaseArray ParseDimension(string indices, int dimlen) { if (indices.Trim() == ":") { return ILMath.full; } int pos = 0, min = 0, max = 0; ILIntList list = ILIntList.Create(); expand(list, ref pos, indices, ref min, ref max, dimlen, 0, false); return list.ToTempArray(); } protected ILSize m_size; /// /// Create trimmed size descriptor from indices in ILRange object /// /// new size descriptor with the neccessary size to define /// an array as defined by all indices in this range internal ILSize Size { get { return m_size; } } #region private helper protected static void extractDimension(ILIntList target, ref int outLen, ILBaseArray A, int dim, ref int min, ref int max, int[] dimensions) { if (object.Equals(A, null)) { return; } using (ILScope.Enter(A)) { int dimLen = dimensions[dim]; if (A is ILDenseArray) { // taken as ':' (i.e.: full) if (dimLen <= 0) return; min = 0; target.Add(-(dimLen - 1)); max = dimLen - 1; outLen += dimLen; } else if (A is ILBaseArray) { (A as ILBaseArray).GetValue(0).Expand(target, ref outLen, ref min, ref max, dimLen - 1); } else if (A is ILDenseArray) { expand(target, ref outLen, A as ILDenseArray, ref min, ref max, dim); } else if (A is ILBaseArray) { if (dimensions[dim] > 0) { Expression exp = (A as ILBaseArray).GetValue(0); int end = ILExpression.Evaluate(exp, dimLen - 1); target.Add(end); outLen++; if (end < min) min = end; if (end > max) max = end; } } else if (A is ILDenseArray) { expand(target, ref outLen, A as ILDenseArray, ref min, ref max, dim); } else if (A is ILDenseArray) { if (!A.IsScalar) throw new ILArgumentException("string index specification: only one string is allowed per dimension"); expand(target, ref outLen, (A as ILDenseArray).GetValue(0), ref min, ref max, (dim < dimensions.Length) ? dimLen : 0, dim, true); } else if (A is ILDenseArray) { expand(target, ref outLen, A as ILDenseArray, ref min, ref max, dim); } else if (A is ILDenseArray) { expand(target, ref outLen, ILMath.find((A as ILDenseArray).C), ref min, ref max, dim); } else if (A is ILDenseArray) { expand(target, ref outLen, A as ILDenseArray, ref min, ref max, dim); } else if (A.Storage is ILCellStorage) { ILCellStorage cellStorage = A.Storage as ILCellStorage; for (int ind = 0; ind < cellStorage.Size.NumberOfElements; ind++ ) { extractDimension(target, ref outLen, cellStorage.GetScalar(ind), dim, ref min, ref max, dimensions); } } else throw new ILArgumentException(String.Format("invalid type of index specification: '{0}'", A.GetType().Name)); } } protected static void expand(ILIntList target, ref int outLen, ILDenseArray A, ref int min, ref int max, int dimIdx) { using (ILScope.Enter(A)) { if (A.IsEmpty) { return; } if (!A.IsVector) throw new ILArgumentException("index specification must be vector sized. found: " + A.Size.ToString()); foreach (/*HC:inArr1*/ double val in A) { /*HC:NaNCheck*/ if (Double.IsInfinity(val) || Double.IsNaN(val)) throw new ILArgumentException("invalid index specification, dimension idx " + dimIdx); Int32 v = (int)val; target.Add(v); if (v < min) min = v; if (v > max) max = v; } outLen += A.Length; } } #region HYCALPER AUTO GENERATED CODE protected static void expand(ILIntList target, ref int outLen, ILDenseArray A, ref int min, ref int max, int dimIdx) { using (ILScope.Enter(A)) { if (A.IsEmpty) { return; } if (!A.IsVector) throw new ILArgumentException("index specification must be vector sized. found: " + A.Size.ToString()); foreach (/*HC:*/ Int64 val in A) { /*HC:NaNCheck*/ if (Double.IsInfinity(val) || Double.IsNaN(val)) throw new ILArgumentException("invalid index specification, dimension idx " + dimIdx); Int32 v = (int)val; target.Add(v); if (v < min) min = v; if (v > max) max = v; } outLen += A.Length; } } protected static void expand(ILIntList target, ref int outLen, ILDenseArray A, ref int min, ref int max, int dimIdx) { using (ILScope.Enter(A)) { if (A.IsEmpty) { return; } if (!A.IsVector) throw new ILArgumentException("index specification must be vector sized. found: " + A.Size.ToString()); foreach (/*HC:*/ Int32 val in A) { /*HC:NaNCheck*/ if (Double.IsInfinity(val) || Double.IsNaN(val)) throw new ILArgumentException("invalid index specification, dimension idx " + dimIdx); Int32 v = (int)val; target.Add(v); if (v < min) min = v; if (v > max) max = v; } outLen += A.Length; } } protected static void expand(ILIntList target, ref int outLen, ILDenseArray A, ref int min, ref int max, int dimIdx) { using (ILScope.Enter(A)) { if (A.IsEmpty) { return; } if (!A.IsVector) throw new ILArgumentException("index specification must be vector sized. found: " + A.Size.ToString()); foreach (/*HC:*/ float val in A) { /*HC:NaNCheck*/ if (Double.IsInfinity(val) || Double.IsNaN(val)) throw new ILArgumentException("invalid index specification, dimension idx " + dimIdx); Int32 v = (int)val; target.Add(v); if (v < min) min = v; if (v > max) max = v; } outLen += A.Length; } } protected static void expand(ILIntList target, ref int outLen, ILDenseArray A, ref int min, ref int max, int dimIdx) { using (ILScope.Enter(A)) { if (A.IsEmpty) { return; } if (!A.IsVector) throw new ILArgumentException("index specification must be vector sized. found: " + A.Size.ToString()); foreach (/*HC:*/ byte val in A) { /*HC:NaNCheck*/ if (Double.IsInfinity(val) || Double.IsNaN(val)) throw new ILArgumentException("invalid index specification, dimension idx " + dimIdx); Int32 v = (int)val; target.Add(v); if (v < min) min = v; if (v > max) max = v; } outLen += A.Length; } } #endregion HYCALPER AUTO GENERATED CODE // parse SINGLE (!) dimension given by string protected static void expand(ILIntList target, ref int outLen, string p, ref int min, ref int max, int dimLen, int dimIdx, bool useFullDimTag) { // possible input: ":", "0:19", "20:-2:5", "1,2,3,4:2:16,end:-2:0,:" if (p.Contains(";")) throw new ILArgumentException("invalid string index specification: ambiguous dimension seperator ';'"); string[] parts = p.Split(','); if (parts.Length == 0) { // empty dimension? return; } else if (parts.Length > 1) { foreach (string part in parts) { expand(target, ref outLen, part, ref min, ref max, dimLen, dimIdx, useFullDimTag); } return; } // only one range specifier if (p.Trim() == ":") { // full dimension if (dimLen <= 0) return; if (useFullDimTag) { target.Add(-(dimLen-1)); } else { for (int i = 0; i < dimLen; i++) { target.Add(i); } } outLen += dimLen; } else { int tmpValue, start, end, step; string[] rngitems = p.Split(':'); switch (rngitems.Length) { case 1: // single number specified if (rngitems[0].Contains("end")) { if (rngitems[0].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; tmpValue = (dimLen-1); } else if (String.IsNullOrWhiteSpace(rngitems[0])) { break; } else if (! int.TryParse(rngitems[0].Trim(),out tmpValue)) { throw new ILArgumentException(String.Format("invalid index for dimension {0}: ({1})", dimIdx,rngitems[0])); } if (tmpValue < min) min = tmpValue; if (tmpValue > max) max = tmpValue; target.Add (tmpValue); outLen++; break; case 2: // unstepped range specified if (rngitems[0].Contains("end")) { if (rngitems[0].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; start = dimLen - 1; } else if (!int.TryParse(rngitems[0],out start)) { throw new ILArgumentException("invalid start index for range in dimension " + dimIdx.ToString()); } if (rngitems[1].Contains("end")) { if (rngitems[1].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; end = dimLen - 1; } else if (!int.TryParse(rngitems[1],out end)) { throw new ILArgumentException("invalid end index for range in dimension " + dimIdx.ToString()); } step = (start <= end) ? 1 : 1; // -1 - make consistent with non-string spec: unspecified step is always 1! if (start<=end) { for (int t = start; t <= end;) { target.Add (t++); } if (start < min) min = start; if (end > max) max = end; outLen += (end-start)+1; } else { //for (int t = start; t >= end;) { // target.Add (t--); //} //if (end < min) min = end; //if (start > max) max = start; //outLen += (start-end)+1 // ^ this is not allowed: unspecified step will always avaluate to 1! } break; case 3: // stepped range specified if (rngitems[0].Contains("end")) { if (rngitems[0].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; start = dimLen - 1; } else if (!int.TryParse(rngitems[0],out start)) { throw new ILArgumentException("invalid start index for range in dimension " + dimIdx.ToString()); } if (rngitems[1].Contains("end")) { if (rngitems[1].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; step = dimLen - 1; } else if (!int.TryParse(rngitems[1],out step)) { throw new ILArgumentException("invalid step index for range in dimension " + dimIdx.ToString()); } if (rngitems[2].Contains("end")) { if (rngitems[2].Trim() != "end") throw new ILArgumentException("index expression evaluation is not supported for string definitions. Use non-string definitions instead!"); if (dimLen <= 0) break; end = dimLen - 1; } else if (!int.TryParse(rngitems[2],out end)) { throw new ILArgumentException("invalid end index for range in dimension " + dimIdx.ToString()); } if (step == 0) { // empty return; } int i = start; if (start == end) { target.Add(start); outLen++; if (start < min) min = start; if (start > max) max = start; } else if (start < end) { if (step < 0) return; for (; i <= end; i += step) { target.Add(i); outLen++; } if (start < min) min = start; if (i - step > max) max = i - step; // cannot compare to end, since it may was not reached! } else { if (step > 0) return; for (; i >= end; i += step) { target.Add(i); outLen++; } if (start > max) max = start; if (i - step < min) min = i - step; } break; default: throw new ILArgumentException("invalid index for dimension " + dimIdx.ToString()); } } } #endregion #region IDisposable Members public void Dispose() { if (m_range != null) { foreach (ILIntList list in m_range) { if (list != null) { list.Dispose(); } } } m_range = null; } #endregion } }