Industrial Data Science
in C# and .NET:
Simple. Fast. Reliable.
 
 

ILNumerics - Technical Computing

Modern High Performance Tools for Technical

Computing and Visualization in Industry and Science

Upgrade Guide ILNumerics V4 -> v5

The following info is a collection of typical steps to be performed when upgrading a project from version 4 to version 5. You may read & check the full list or use it as a reference for searching specific term / function names etc. This list has been assembled based on feedback from customers during a prerelease phase for version 5. Commonly, only the first 6..7 points will apply to your project, though:

  1. Retarget your project to use at least .NET Framework 4.5.2. In Visual Studio -> Solution Explorer -> double click on the project's Properties node -> Application -> Target framework. If no framework >= 4.5.2 is installed, go ahead and make a concious decision about which framework to target. We (and Microsoft) recommend to target the latest framework available. Download + install this .NET framework using the official installer.
  2. Make sure ILNumerics version 5 is installed and the correct ILNumerics modules version 5 are referenced. Currently, this may requires to remove older references from your project and to add version 5 references from [Add References] dialog in Visual Studio.
  3. Add the recommended namespaces, include the recommended static tool classes. See:

    Computing Engine - Setup & Rules

  4. Refresh your licenses in Visual Studio -> Options -> ILNumerics -> Licenses.

  5. Remove the “IL” prefix from ALL class names. A rather painless way is to use the Visual Studio IDE. Just copy the below regular expression into the search box of the Quick Replace toolwindow in Visual Studio:

\b(|I)IL(?(Numerics|Math\b|Lic|NLic|NDo|NHelp|ist|NCH|Temp)|(\w*))\b

-> $1$2

Make sure that both buttons: "Aa" (case sensitivity) and ".*" (regexp) from the bottom row in the tool window are selected and that the button "Ab|" (whole word) is not selected! Hit "Replace All".

 

The above regular expression has proven to be working out for most 'regular' projects / algorithms. Some customers, however, reported problems related to large projects with many custom types having similar names as ILNumerics types. In this case you may try to adopt the above regular expression, to exclude more types from the filter expression (by adding them inside the '?(...)' negating parenthesis), or to start with another, more explicit expression right from the start: 

 

\bIL((Array|InArray|OutArray|RetArray|Logical|InLogical|OutLogical|RetLogical|Scope|BaseArray|Size|Panel|Scene|Node|PlotCube|Legend|LegendItem|LinePlot|Surface|CountourPlot|ImageSCPlot|Label|Colormap|Limits))\b

-> $1
  1. ILNumerics’ specific exceptions have been removed and replaced with common .NET exceptions. The class reference / Intellisense provides details about when which exception is thrown. Most places will generate ArgumentException or IndexOutOrRangeException, some throw InvalidOperationException or NotSupportedException.
  2. long is the new int! Array elements are indexed via long indices in version 5. A number of exception is provided for compatibility and for performance. But in general, the length of a dimension is expressed as long /Int64 value. Likewise, the length returned from the A.Size[i] & A.S[i] indexers is now long. In most cases you can simply change the declaration of local int variables to 'var' and fix any upcoming errors in the code below. Otherwise, of course, casting back down to int is possible, too. But keep in mind: the correct type is ‘Int64’! There must be a good reason to downcast a dimension length. We recommend to stay with ‘long’ and be prepared for huge arrays whenever possible.  
  3. Casting from multidimensional System.Array:

Compared to version 4 A is no longer transposed in version 5. It is converted to an ILNumerics array [4x3] with row major storage. In version 4, however, arrays had to be defined with dimensions flipped. Potentially, many codes today show the flipped version, still. Thus we need a way of easily flipping the definition of the multidim .NET initializers:

Solution 1: use vector<T>(…).Reshape(…) instead. This is fast but requires some refactoring work:

 Solution 2: leaves the original expression untouched, wraps it into array(...).T

Since the second solution first creates a temporary .NET array and copies it into a new ILNumerics array afterwards you may go with the first solution in high performance scenarios. On the other hand, such explicit array initializers tend to be relatively small so that performance may not be an issue here.

  1. Compiler error: CS0217 – “In order to be applicable as a short circuit operator a user-defined logical operator &(ConcreteArray<…>, ConcreteArray<…>)') must have the same return type and parameter types”   Fix this by explicitly down-casting (at least one of) the ILNumerics array operands to (bool):
  1. The memory pool has been changed to store MemoryHandles instead of System.Array. A common pattern to use the pool in version 4 was to fetch a pooled T[] array, to work with it and give it back to the pool afterwards. This scheme is now discouraged. If possible leave all memory management to the arrays and use A.GetHostPointerForRead() or A.GetHostPointerForWrite() instead. If you still want to resort back to the "allocate - free" scheme see here.
  2. vec<T>(start,[step,] end) is replaced by arrange<T,TStep>(T Start, TStep step, T End). Ex: vec<double>(1.0, -1.0, 1.0, 5.0) -> arrange(1.0, -1.0, 1.0, 5.0) , i.e.: simply replace ‘vec’ with ‘arange’. Make sure, though, to remove the (single) generic type definition left over from vec<T>() in order for the compiler to pick up the types from the given parameter values! Alternatively, specify both type definitions as required for ‘arange<T,TStep>(…)’ explicitly.
  3. repmat<float>(A, 3,2) -> repmat(A, 3, 2) or repmat(A, size(3, 2))
  4. horzcat(A,B,C,D) -> horzcat(A,horzcat(B,horzcat(C,D)));
  5. vertcat(A, B, C, D) -> vertcat(A,vertcat(B,vertcat(C,D)));
  6. Array<int> I = find(A): find() and other functions dealing with indices are now prepared for huge arrays. They return OutArray<long> as Indices parameter. For find(), however, a compatibility function is provided which allows one to stay on Int32 indices with minimal changes: I = find32(A).
  7. max(A, I: I) & min(A, I: I), I was <int>, change I to <long>! Similar: indices returned from sort(A,I): change the index (output) array from Array<int> -> to Array<long>.
  8. flipup(), fliplr() -> remove unneeded generic type specifiers.
  9. Subarrays have been reworked and could be significantly improved. We believe that we achieved (nearly?) the best one can do with “subarray-ing” – without giving up on backwards compatibility. We now utilize compiler overloading (at compile time!) in order to pick the best overload for the given subarray index types. All former indexing features are still available and you do not need to change your code. However, read here for all indexing options and their implication on performance in order to profit from a significant speedup in many common cases.
  10. The concept of ‘singleton dimensions’ in an array has changed. Until version 4 only those dimensions were considered as ‘non-singleton’ dimensions, which had a length greater than one. Now, any dimension with a length not equal to one is considered a non-singleton dimension. This change affects empty dimensions (length 0), which in version 5 count as non-singleton dimensions, while in version 4 they did not.
  11. ILNumerics.ILMath and all toolboxes classes are now static classes! Instead of deriving your computational classes from them (exactly: from a single one of them, as recommended in version 4) you may now pick several of ILMath and/or other toolbox classes in order to include their functions into your code scope. Instead of deriving from them in version 5 you may use the 'using static ILNumerics.ILMath'  directive at the beginning of your code file. Furthermore: some useful constants moved from ILMath into a new static ILNumerics.Globals class: pi, pif, full, end, eps. All subarray range / slice functions live here too. It is recommended to always import this class at the beginning of your code: 'using static ILNumerics.Globals;'. See also: Computing Engine General Setup
  12. any(), all() – handling of NaN / Inf values changed: In version 4 NaNs were excluded from comparisons while in version 5 NaN is now considered ‘not zero’. Hence, it evaluates to true in any() and all().
  13. All accumulating functions reducing a whole array to a single value (sumall, allall, anyall) now always return a scalar. In earlier versions empty arrays returned an empty array. In version 5 empty input causes a scalar with the default data type value to be returned. (false / zero 0).
  14. All interfaces exposing / expecting managed arrays have been changed to pointers of the corresponding concrete elementary system scalar value type (double[] A -> double*). This mostly affects ILNumerics.Native.ILapack, and the low-level FFT interfaces.
  15. When using an initialization function be careful when specifying the last dimension as 0! empty<T>(1, 0); or rand(1, 0); does not produce the expected result! The trailing ‘0’ leads the compiler into ambiguities or even into favoring a wrong overload (sic):Solution: name the last parameter -> empty<T>(i, d1: 0); Note: this issues only exists for a trailing ‘0’. Non-0 dimension lengths have no issue. Update v5.1: For such functions providing a 'params long[] dims' overload, the compiler may encounters an ambiguity. Resolve this, again, by explicitly naming at least the last dimension (having the value 0): rand(0, 2, d2:0). Again, this of course is only an issue when creating empty arrays this way, which is rather uncommon anyways.
  16. object.Equals(A,B) on ILNumerics arrays A and B: A and B are considered equal if their types, element values and shapes are equal. Shapes are compared using Size.IsSameSize(), which is less strict than Size.IsSameShape(). I.e.: singleton dimensions are ignored if all remaining dimensions match. Empty arrays are handled in the same way: all non-singleton dimensions must match in order for A and B to be considered ‘equal’.
  17. Deciding for an ArrayStyle: when converting your code from version 4 -> version 5 you will likely always chose ArrayStyles.ILNumerics. This gives you compatibility with the version 4 semantics on indexing operations, regarding the (default) storage orders and other array properties. However, consider designing your function for multiple array styles! At best, do not impose any array style for your function. Check, if the function really relies on a certain array style. If it does, use the optional parameter of using (Scope.Enter(A1,A2, StorageOrders.ILNumericsV4)) {… to lock the array style for your function body. Otherwise, just leave the function as it is, not mentioning any array style property. Read more: function rules & scope blocks.
  18. broadcasting is more strict in version 5: when operating two vectors of the same lengths but different orientation, the orientation is exactly considered. (was: the result in version 4 was a vector). A matrix is now produced.
  19. creation functions zeros(4), ones(4) are now more strict: a single dimension argument leads to the creation of a square matrix (just as in Matlab). Use vector(), empty() or array() to create true 1D vectors (in numpy mode only). Otherwise, specify a trailing, singleton dimension explicitly. Ex: ILMath.ones<float>(4,1) -> vector of 1’s, size [4,1]. ILMath.ones<float>(4) -> matrix of 1’s, size [4,4] !!
  20. Sizes are now Array<long>(): Use vector<long>(2,3,4) or size(2,3,4) to replace the old style (was: 'new ILSize(2,3,4)'). This also applies to distribution functions in the Statistics Toolbox and to other places. In order to provide the shape of an existing array A use A.shape. Note: prodall(s) gives the number of elements in an array A of size s, where A.S.NumberofElements is not an option for some reasons.
  21. The former function ILMath.size(A,dim), returning the length of dimension dim of A is gone. Use A.S[dim] instead. 
  22. Cell arrays have been reworked, too. In version 4 a cell storing the arrays A and B was created by cell(A,B) or by new ILCell(A,B). In version 5, in general, use: cellv(A,B); instead. The cell() function now serves a more general purpose of creating cell arrays of predefined size and/or predefined content. See: cell arrays.

Visualization module:

  1. The removal of the “IL” prefix may cause a couple of ambiguous references with the classes from Windows.Forms and / or System.Drawing. Just be more explicit and use the full namespace when required. Ex:
  • ILLabel -> ILNumerics.Drawing.Label
  • ILPanel -> ILNumerics.Drawing.Panel
  • ILSize -> ILNumerics.Drawing.Size (or even better: use Array<long> s = ILMath.size() for all sizes!)
  1. ILPanel.Driver  was renamed to -> Panel.RendererType. This may affect code in *.Designer.cs files, too. Just follow the compiler errors to find the errorneous line and replace the name to 'RendererType'.

See also:

In case that you encounter any issue not listed here please let us know: support@ilnumerics.net