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 |
|
---|
40 | using System;
|
---|
41 | using System.Collections.Generic;
|
---|
42 | using ILNumerics.Storage;
|
---|
43 | using System.IO;
|
---|
44 | using ILNumerics.Exceptions;
|
---|
45 |
|
---|
46 | namespace ILNumerics {
|
---|
47 | [System.Diagnostics.DebuggerTypeProxy(typeof(ILNumerics.Misc.ILArrayDebuggerProxy<>))]
|
---|
48 | [System.Diagnostics.DebuggerDisplay("{ShortInfo(),nq}")]
|
---|
49 | [Serializable]
|
---|
50 | // ToDo: DOKU for ILDenseArray<ElementType> missing
|
---|
51 | public partial class ILDenseArray<ElementType> : ILBaseArray<ElementType> {
|
---|
52 |
|
---|
53 | #region constructors
|
---|
54 | internal ILDenseArray(ILStorage storage, bool isTempArray)
|
---|
55 | : base(storage, isTempArray) {
|
---|
56 |
|
---|
57 | }
|
---|
58 | #endregion
|
---|
59 |
|
---|
60 | #region properties
|
---|
61 | /// <summary>
|
---|
62 | /// internal access to the underlying storage
|
---|
63 | /// </summary>
|
---|
64 | internal new ILDenseStorage<ElementType> Storage {
|
---|
65 | get { return (m_storage as ILDenseStorage<ElementType>); }
|
---|
66 | set {
|
---|
67 | // e.g. Storage.Detach() may return itself (if no detaching is
|
---|
68 | // required). So we must check for that equalty here!
|
---|
69 | if (!object.Equals(value, m_storage)) {
|
---|
70 | m_storage.Dispose();
|
---|
71 | m_storage = value;
|
---|
72 | }
|
---|
73 | }
|
---|
74 | }
|
---|
75 | /// <summary>
|
---|
76 | /// Clone of this array (fast, lazy and shallow)
|
---|
77 | /// </summary>
|
---|
78 | public virtual ILRetArray<ElementType> C {
|
---|
79 | get {
|
---|
80 | return new ILRetArray<ElementType>((ILDenseStorage<ElementType>)Storage.Clone());
|
---|
81 | }
|
---|
82 | }
|
---|
83 | /// <summary>
|
---|
84 | /// Return transposed version of this array
|
---|
85 | /// </summary>
|
---|
86 | /// <remarks>For matrices, this swaps columns with rows. For arrays, the dimensions are shifted by one.
|
---|
87 | /// <para>Note, for complex elements, <b>no</b> conjugate is created! Use conj(A.T) if this is intended.</para></remarks>
|
---|
88 | public ILRetArray<ElementType> T {
|
---|
89 | get {
|
---|
90 | // if this is updated to create a conjugate for complex data types
|
---|
91 | // -> do not forget to update quick reference ILNumerics4Matlab also!
|
---|
92 | return new ILRetArray<ElementType>(Storage.ShiftDimensions(1));
|
---|
93 | }
|
---|
94 | }
|
---|
95 | /// <summary>
|
---|
96 | /// [deprecated] Get maximum value of array - if any
|
---|
97 | /// </summary>
|
---|
98 | /// <remarks>This property is marked as deprecated and will be removed in a future version. Use one of the
|
---|
99 | /// following alternatives instead:
|
---|
100 | /// </remarks>
|
---|
101 | /// <seealso cref="ILNumerics.ILBaseArray<ElementType>.GetLimits(out ElementType, out ElementType)"/>
|
---|
102 | [Obsolete()]
|
---|
103 | public ElementType MaxValue {
|
---|
104 | get {
|
---|
105 | ElementType ret, dummy;
|
---|
106 | GetLimits(out dummy, out ret);
|
---|
107 | return ret;
|
---|
108 | }
|
---|
109 | }
|
---|
110 | /// <summary>
|
---|
111 | /// [deprecated] Get minimum value of array - if any
|
---|
112 | /// </summary>
|
---|
113 | /// <remarks>This property is marked as deprecated and will be removed in a future version. Use one of the
|
---|
114 | /// following alternatives instead:
|
---|
115 | /// <list type="bullets">
|
---|
116 | /// <item><seealso cref="ILNumerics.ILBaseArray{T}.GetLimits"/></item>
|
---|
117 | /// <item><seealso cref="ILNumerics.ILMath.minall"/></item>
|
---|
118 | /// </list></remarks>
|
---|
119 | [Obsolete()]
|
---|
120 | public ElementType MinValue {
|
---|
121 | get {
|
---|
122 | ElementType ret, dummy;
|
---|
123 | GetLimits(out ret, out dummy);
|
---|
124 | return ret;
|
---|
125 | }
|
---|
126 | }
|
---|
127 | #endregion
|
---|
128 |
|
---|
129 | #region memory management
|
---|
130 | /// <summary>
|
---|
131 | /// Get number of arrays, referencing the same underlying data storage
|
---|
132 | /// </summary>
|
---|
133 | /// <return>This number is always greater than or equal to 1.</return>
|
---|
134 | /// <remarks>For temporary arrays, calling this property does not - as usual -
|
---|
135 | /// disposes the array</remarks>
|
---|
136 | public int ReferenceCount {
|
---|
137 | get {
|
---|
138 | return Storage.ReferenceCount;
|
---|
139 | }
|
---|
140 | }
|
---|
141 |
|
---|
142 | #endregion
|
---|
143 |
|
---|
144 | #region public function
|
---|
145 | /// <summary>
|
---|
146 | /// Clone of this array
|
---|
147 | /// </summary>
|
---|
148 | /// <remarks><para>
|
---|
149 | /// Clones of all arrays in ILNumerics are done in a very fast, lazy way. This means,
|
---|
150 | /// at the time the clone is made, no relevant memory is copied. Elements of both arrays rather point to the same
|
---|
151 | /// underlying System.Array. A reference counting mechanism ensures the detaching of thoses arrays
|
---|
152 | /// on write access.</para>
|
---|
153 | /// <para>The clone returned will be of the same type as this instance.</para></remarks>
|
---|
154 | internal override ILBaseArray Clone() {
|
---|
155 | ILRetArray<ElementType> ret = new ILRetArray<ElementType>((ILDenseStorage<ElementType>)Storage.Clone());
|
---|
156 | return ret;
|
---|
157 | }
|
---|
158 | /// <summary>
|
---|
159 | /// Concatenate this array
|
---|
160 | /// </summary>
|
---|
161 | /// <param name="A">N-dimensional array. Except for dimensions <paramref name="dim"/>
|
---|
162 | /// the dimensions of A must match the dimensions of this storage</param>
|
---|
163 | /// <param name="dim">Index of dimension to concatenate arrays along.
|
---|
164 | /// If dim is larger than the number of dimensions of any of the arrays,
|
---|
165 | /// its value will be used in modulus the number of dimensions.</param>
|
---|
166 | /// <returns>New array having the size
|
---|
167 | /// of both input arrays layed behind each other along the dim's-dimension</returns>
|
---|
168 | public ILRetArray<ElementType> Concat(ILInArray<ElementType> A, int dim) {
|
---|
169 | using (ILScope.Enter(A))
|
---|
170 | return new ILRetArray<ElementType>(Storage.Concat(A.Storage, dim));
|
---|
171 | }
|
---|
172 | /// <summary>
|
---|
173 | /// Copy values of all elements into System.Array.
|
---|
174 | /// </summary>
|
---|
175 | /// <param name="outArray">[Output] System.Array, holding all element values of this ILDenseStorage.</param>
|
---|
176 | /// <remarks>The System.Array may be predefined. If its length is sufficient, it will be used and
|
---|
177 | /// its leading elements will be overwritten when function returns. If 'outArray' is null or has too few elements,
|
---|
178 | /// it will be recreated from the ILNumerics memory pool.</remarks>
|
---|
179 | public void ExportValues(ref ElementType[] outArray) {
|
---|
180 | Storage.ExportValues(ref outArray);
|
---|
181 | }
|
---|
182 | /// <summary>
|
---|
183 | /// Get direct reference to inner System.Array storage for <b>read access</b> - use with care!
|
---|
184 | /// </summary>
|
---|
185 | /// <returns>Reference to inner System.Array for reading</returns>
|
---|
186 | /// <remarks>This method is provided for experts only! Altering elements of this
|
---|
187 | /// array may cause the data to be invalidated or corrupted! Use this array only for reading! Note
|
---|
188 | /// the ILNumerics array storage format (column major). Keep in mind, the length
|
---|
189 | /// of the array may exceeds the number of elements!
|
---|
190 | /// <para>Accessing the inner system array directly should be left to ILNumerics experts only!
|
---|
191 | /// Unless you really know, what you are doing, you should rather use the higher order access
|
---|
192 | /// methods provided by ILArray<T>!</para>
|
---|
193 | /// <para>Unlike (almost) all other member function of an array, this function
|
---|
194 | /// does not keep track of internal memory management. It means, the storage which this array is based
|
---|
195 | /// upon, will not be set free after the function returns. You (as the user of the array) will have to pay
|
---|
196 | /// attention yourself, when to call dispose on the array - if necessary. Also, for elements of reference
|
---|
197 | /// types (e.g. ILCell), retrieving and storing elements from/into the System.Array directly does
|
---|
198 | /// not simulate a value semantic as all other functions do! This means, references are copied. Attention
|
---|
199 | /// must be paid to dereference / clone elements accordingly. </para></remarks>
|
---|
200 | public ElementType[] GetArrayForRead() {
|
---|
201 | return Storage.GetArrayForRead();
|
---|
202 | }
|
---|
203 | /// <summary>
|
---|
204 | /// Direct reference to inner System.Array storage for write access - use with care!
|
---|
205 | /// </summary>
|
---|
206 | /// <returns>Reference to inner System.Array</returns>
|
---|
207 | /// <remarks>Altering this array can be done directly. If necessary, the array is detached before
|
---|
208 | /// returned. Watch the column order format of storages in ILNumerics. Keep in mind, the length
|
---|
209 | /// of the System.Array may exceed the number of elements of the ILNumerics array.
|
---|
210 | /// <para>Accessing the inner system array directly should be left to ILNumerics experts only.
|
---|
211 | /// Unless you really know, what you are doing, you should rather use the higher order access
|
---|
212 | /// methods provided by ILArray<T>!</para>
|
---|
213 | /// <para>Unlike (almost) all other member function of an array, this function
|
---|
214 | /// does not keep track of internal memory management. It means, the storage which this array is based
|
---|
215 | /// upon, will not be set free after the function returns. You (as the user of the array) will have to pay
|
---|
216 | /// attention yourself, when to call dispose on the array - if necessary. Also, for elements of reference
|
---|
217 | /// types (e.g. ILCell), retrieving and storing elements from/into the System.Array directly does
|
---|
218 | /// not simulate a value semantic as all other functions do! This means, references are copied. Attention
|
---|
219 | /// must be paid to dereference / clone elements accordingly. </para></remarks>
|
---|
220 | public ElementType[] GetArrayForWrite() {
|
---|
221 | return Storage.GetArrayForWrite();
|
---|
222 | }
|
---|
223 | /// <summary>
|
---|
224 | /// Enumerator returning elements as ElementType
|
---|
225 | /// </summary>
|
---|
226 | /// <returns>Enumerator</returns>
|
---|
227 | /// <remarks>This method enables the use of ILNumerics arrays in foreach loops.
|
---|
228 | /// <para>The iterator is returned, if arrays are directly used in foreach statements. The iterator
|
---|
229 | /// is compatible with ILNumerics memory management.</para></remarks>
|
---|
230 | /// <example><code>ILArray<double> A = rand(5,4,6);
|
---|
231 | /// foreach (double element in A) {
|
---|
232 | /// // all elements are scalar double values
|
---|
233 | /// String.Format("Element: {0} ", element);
|
---|
234 | /// // Note: 'element' cannot be used to alter the collection!
|
---|
235 | /// } </code>
|
---|
236 | /// </example>
|
---|
237 | public override IEnumerator<ElementType> GetEnumerator() {
|
---|
238 | ElementType[] values = GetArrayForRead();
|
---|
239 | int len = Size.NumberOfElements;
|
---|
240 | for (int i = 0; i < len; i++)
|
---|
241 | yield return values[i];
|
---|
242 | }
|
---|
243 | /// <summary>
|
---|
244 | /// Gives away internal storage for further use (e.g. in ILArray), disposes this array
|
---|
245 | /// </summary>
|
---|
246 | /// <returns>Internal storage</returns>
|
---|
247 | internal ILDenseStorage<ElementType> GiveStorageAwayOrClone() {
|
---|
248 | if (m_scopeCounter <= 0) {
|
---|
249 | ILDenseStorage<ElementType> ret = Storage;
|
---|
250 | m_storage = null;
|
---|
251 | return ret;
|
---|
252 | } else {
|
---|
253 | return (ILDenseStorage<ElementType>)Storage.Clone();
|
---|
254 | }
|
---|
255 | }
|
---|
256 | /// <summary>
|
---|
257 | /// Create replication of this array
|
---|
258 | /// </summary>
|
---|
259 | /// <param name="dims">Dimensions specifier. If the number of elements in <paramref name="dims"/> is
|
---|
260 | /// less than the number of dimensions in this array, the trailing dimensions will
|
---|
261 | /// be set to 1 (singleton dimensions). On the other hand, if the number specified
|
---|
262 | /// is larger then the number of dimension stored inside the storge the resulting
|
---|
263 | /// storage will get its number of dimensions extended accordingly. </param>
|
---|
264 | /// <returns>Array being created by multiple replications of this array along
|
---|
265 | /// arbitrary dimensions according to <paramref name="dims"/></returns>
|
---|
266 | internal ILRetArray<ElementType> Repmat(params int[] dims) {
|
---|
267 | return new ILRetArray<ElementType>(Storage.Repmat(dims));
|
---|
268 | }
|
---|
269 | /// <summary>
|
---|
270 | /// Reshaped copy of this array
|
---|
271 | /// </summary>
|
---|
272 | /// <param name="dimensions">New dimensions of the array</param>
|
---|
273 | /// <returns>Reshaped copy of the array</returns>
|
---|
274 | /// <remarks><para>The current instance will not be changed. A new storage is created, having
|
---|
275 | /// the elements of this array and a shape as determined by <paramref name="dimensions"/>.</para>
|
---|
276 | /// </remarks>
|
---|
277 | /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the number of elements in <paramref name="dimensions"/>
|
---|
278 | /// do not match the number of elements in this array.</exception>
|
---|
279 | public ILRetArray<ElementType> Reshape(ILSize dimensions) {
|
---|
280 | using (ILScope.Enter()) {
|
---|
281 | ILArray<ElementType> ret = C;
|
---|
282 | ret.Storage.Reshape(dimensions);
|
---|
283 | return ret;
|
---|
284 | }
|
---|
285 | }
|
---|
286 | /// <summary>
|
---|
287 | /// Reshaped copy of this array
|
---|
288 | /// </summary>
|
---|
289 | /// <param name="dimensions">New dimensions of the array</param>
|
---|
290 | /// <returns>Reshaped copy of the array</returns>
|
---|
291 | /// <remarks><para>The current instance will not be changed. A new array is created, having
|
---|
292 | /// the elements of this array and a shape as determined by <paramref name="dimensions"/>.</para>
|
---|
293 | /// </remarks>
|
---|
294 | /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the number of elements in 'newDimension'
|
---|
295 | /// do not match the number of elements in this array.</exception>
|
---|
296 | public ILRetArray<ElementType> Reshape(params int[] dimensions) {
|
---|
297 | return Reshape(new ILSize(dimensions));
|
---|
298 | }
|
---|
299 | /// <summary>
|
---|
300 | /// Subarray creation
|
---|
301 | /// </summary>
|
---|
302 | /// <param name="size">Range specification, defining the size of the subarray</param>
|
---|
303 | /// <returns>Subarray as copy of a part of this array</returns>
|
---|
304 | /// <remarks>Consult the ILNumerics subarray documentation for all subarray indexing rules.</remarks>
|
---|
305 | public ILRetArray<ElementType> Subarray(params ILBaseArray[] size) {
|
---|
306 | using (ILScope.Enter(size))
|
---|
307 | return new ILRetArray<ElementType>(Storage.Subarray(size));
|
---|
308 | }
|
---|
309 | /// <summary>
|
---|
310 | /// Create array from this array and shift dimensions
|
---|
311 | /// </summary>
|
---|
312 | /// <param name="shift">Number of dimensions to shift</param>
|
---|
313 | /// <returns>Shifted version of this array</returns>
|
---|
314 | /// <remarks><para>The shift is done 'to the left':</para>
|
---|
315 | /// <example><code>ILArray<double> A = zeros(2,4);
|
---|
316 | /// ILArray<double> B = A.Shifted(1);
|
---|
317 | /// // B is now: <double> [4,2]
|
---|
318 | ///
|
---|
319 | /// ILArray<double> C = zeros(2,4,3);
|
---|
320 | /// ILArray<double> D = C.Shifted(1);
|
---|
321 | /// // D is now: <double> [4,3,2]
|
---|
322 | /// </code></example>
|
---|
323 | /// <para>The dimensions are shifted circulary to the left. This
|
---|
324 | /// can be imagined as removing the first dimensions from the beginning of the list of
|
---|
325 | /// dimensions and "append" them to the end in a ringbuffer style.</para>
|
---|
326 | /// <para>For dimension shifts of '1', you may consider using the
|
---|
327 | /// <see cref="ILNumerics.ILDenseArray{ElementType}.T"/> property for readability.</para>
|
---|
328 | /// <para><paramref name="shift"/> must be positive. It is taken modulus the number of dimensions.</para>
|
---|
329 | /// <seealso cref="ILNumerics.ILDenseArray{ElementType}.T"/></remarks>
|
---|
330 | public ILRetArray<ElementType> Shifted(int shift) {
|
---|
331 | return new ILRetArray<ElementType>(Storage.ShiftDimensions(shift));
|
---|
332 | }
|
---|
333 | /// <summary>
|
---|
334 | /// Send values of this instance to stream.
|
---|
335 | /// </summary>
|
---|
336 | /// <param name="stream">Stream to write the values into.</param>
|
---|
337 | /// <param name="format">Format string to be used for output. See <see cref="System.String.Format(string,object)"/> for a specification
|
---|
338 | /// of valid formating expressions. This flag is only used, when 'method' is set to 'Serial'.</param>
|
---|
339 | /// <param name="method">A constant out of <see cref="ILArrayStreamSerializationFlags"/>. Specifies the way in which
|
---|
340 | /// the values will be serialized.</param>
|
---|
341 | /// <remarks><para>If the 'Formatted' method is used, any occurences of the NewLine character(s)
|
---|
342 | /// will be replaced from the format string before applying to the elements. This is done to
|
---|
343 | /// prevent the format from breaking the 'page' style of the output.</para>
|
---|
344 | /// <para>If 'method' is set to 'Matlab', the array will be written as Matfile version 5.0. No compression will be used. The internal 'Name' property will be used as the
|
---|
345 | /// array name for writing. This array instance will be the only array in the .mat file. If you want to write several arrays bundled into one mat file, use the MatFile class to
|
---|
346 | /// create a collection of arrays and write the MatFile to stream.</para></remarks>
|
---|
347 | public override void ToStream(Stream stream, string format, ILArrayStreamSerializationFlags method) {
|
---|
348 | try {
|
---|
349 | int len;
|
---|
350 | switch (method) {
|
---|
351 | case ILArrayStreamSerializationFlags.Serial:
|
---|
352 | len = Size.NumberOfElements;
|
---|
353 | using (TextWriter tw = new StreamWriter(stream)) {
|
---|
354 | for (int i = 0; i < len; i++) {
|
---|
355 | tw.Write(format, GetValue(i));
|
---|
356 | }
|
---|
357 | }
|
---|
358 | break;
|
---|
359 | case ILArrayStreamSerializationFlags.Formatted:
|
---|
360 | format = format.Replace(Environment.NewLine, "");
|
---|
361 | ILDenseStorage<ElementType> temp = this.Storage.ShiftDimensions(1);
|
---|
362 | //len = Dimensions.NumberOfElements / Dimensions[1];
|
---|
363 | using (TextWriter tw = new StreamWriter(stream)) {
|
---|
364 | tw.Write(temp.ValuesToString(0));
|
---|
365 | }
|
---|
366 | break;
|
---|
367 | case ILArrayStreamSerializationFlags.Matlab:
|
---|
368 | ILMatFile mf = new ILMatFile(new ILBaseArray[1] { this });
|
---|
369 | mf.Write(stream);
|
---|
370 | break;
|
---|
371 | }
|
---|
372 | } catch (Exception e) {
|
---|
373 | throw new ILException("ToStream: Could not serialize to stream.", e);
|
---|
374 | }
|
---|
375 | }
|
---|
376 | /// <summary>
|
---|
377 | /// Give that storage away for in-place operations, if possible (depends on scope and temp type of array)
|
---|
378 | /// </summary>
|
---|
379 | /// <returns>true if the storage of the array is about to get disposed anyway</returns>
|
---|
380 | /// <remarks>The function investigates the state of the array. If this is a temporary array in
|
---|
381 | /// the outer most scope, it would get disposed after the </remarks>
|
---|
382 | internal bool TryGetStorage4InplaceOp(out ElementType[] array) {
|
---|
383 | // check if this array is yet to be available
|
---|
384 | if (!Settings.AllowInArrayAssignments && m_isTempArray && m_scopeCounter <= 1) {
|
---|
385 | // it's efficient only if we dont have to make a copy of the underlying array
|
---|
386 | if (Storage.ReferenceCount == 1) {
|
---|
387 | ILDenseStorage<ElementType> storage = Storage;
|
---|
388 | m_storage = null;
|
---|
389 | array = storage.GetArrayForWrite();
|
---|
390 | return true;
|
---|
391 | }
|
---|
392 | }
|
---|
393 | array = null;
|
---|
394 | return false;
|
---|
395 | }
|
---|
396 | #endregion
|
---|
397 | }
|
---|
398 | }
|
---|