System.Numerics.Complex vs. complex
  • I found that ILNumerics provides complex and fcomplex types. None of these seem to be compatible with System.Numerics.Complex provided by the .net 4 framework. Can I use ILArray with System.Numerics.Complex? Or should I avoid that? It seems that there is not even a constructor for complex taking the frameworks Complex as a parameter. Not to mention any implicit conversion support. Am I missing something here?
  • System.Numerics.Complex is not used within ILNumerics. Several arguments led to this decision:

    * lag of single precision support
    * many edge cases not defined (rel. to handling operations involving NaN, Inf, 0)
    * occasionally incompatible results compared to Matlab, octave, IlNumerics, etc
    * the storage layout must be fixed in order to be used in native LAPACK libraries [Edit: The memory layout of System.Numerics.Complex actually is compatible to the C/FORTRAN style.]
    * downwards compatibility reasons with existing ILNumerics code

    However, the type of course can be used in conjunction with ILArray. But it will not be supported in builtin functions. Maybe a conversion function would be a useful feature for a future release? but why would someone need Numerics.Complex if there is ILNumerics.complex ?

    ILMath.ToNumericsComplex(...)
  • Ok, thats more or less what I expected. Thanks. I will simply add an extension method to provide convenient conversion in my project.

    > but why would someone need Numerics.complex if there is ILNumerics.Complex ?

    Because the type is used in other parts of the code and esp. because it is used/returned by another more specialized library for image processing.

    Your library is really great, but it does not provide any higher-level algorithms. What means, in many projects one has to use it in conjunction with other libraries. IMO its good practice for a library to support interfacing "native" .net types.
  • > IMO its good practice for a library to support interfacing "native" .net types.

    I complete agree on that point: it is cumbersome to convert between native and ILNumerics complex types and there is good reason to support native types.

    We will check whether we can add at least basic support for
    ILArray<System.Numerics.Complex>.
    However, as haymo mentioned there might be severe limitations for using MKL/Lapack code.
  • >> but why would someone need Numerics.complex if there is ILNumerics.Complex ?
    >Because the type is used in other parts of the code and esp. because it is
    >used/returned by another more specialized library for image processing.
    That makes sense. The basic support mentioned above IMO should include (t.b. appended):

    * ILMath.tocomplex(Numerics.Complex[])
    * ILMath.tocomplex(Numerics.Complex[,])
    * ILMath.tocomplex(Numerics.Complex[,,])
    * ILArray.ExportValues(ref Numerics.Complex[])
    * new ILNumerics.complex(Numerics.Complex) constructor
    * ... (?)

    Therefore, the support would be limited to converting to/from those types and ILNumerics arrays.
  • Constructors same as ILMath.tocomplex:
    new ILNumerics.complex(Numerics.Complex[]) constructor
    new ILNumerics.complex(Numerics.Complex[,]) constructor
    new ILNumerics.complex(Numerics.Complex[,,],n,m,...) constructor

    Implicit element-wise conversion (not critical, but very helpful):

    ILArray a = new System.Numerics.Complex(real, imag);
    ILArray a = new System.Numerics.Complex[...];
    a[i,j] = new System.Numerics.Complex(real, imag);
    a[range] = new System.Numerics.Complex[...];

    Of course, these could be replaced by something like this:

    a[i,j] = new ILNumerics.complex(new System.Numerics.Complex(real, imag)); or
    a[i,j] = ILMath.tocomplex(new System.Numerics.Complex(real, imag));

    But helpful, anyway ... esp. for subarray assignment
  • Also, instead of ILArray.ExportValues(ref Complex[]), it would be more convenient to have
    Complex[] a = ILArray.ToComplex(); and
    Complex[,] a = ILArray.ToComplex(n,m); etc.

    It nicely compacts

    Complex[] b = new ...
    a.ExportValues(ref b);
    MyFunction(b);

    to this

    MyFunction(a.ToComplex(n,m));

    (This one applies to other supported types as well and probably should be discussed in a different thread?)
  • Thanks, twemg! I could imagine, having distinct extension methods on 'ILArray<T>.ToArray()' for common element types T: double, float, complex, fcomplex, int32, int64. By using extension methods, we gain the flexibility, to have those method only for selected ILArray with relevant generic argument types (and not on - lets say ILArray<string>). Also we therefore can return another type than the inner element type. For the 'Complex'-issue we would get:

    System.Numerics.Complex[] ILArray<ILNumerics.complex>.ToArray()

    However, some obstacles exist also:
    Confusion due to the naming is likely. Maybe we can find a better name: ToSystemArray() -> but this looks lengthy ... :|

    Another issue might arise related to the memory management. ILNumerics archieves complete recycling of inner storages. By giving away a storage to our .ToSystemArray() method, this memory is either lost (-> bad for performance) or the user will have to keep track of it and return it manually to the ILNumerics memory pool (with the risk of forgetting).

    This was the reason for the cumbersome ExportValues(ref ..). Since for many real world scenarios, those conversions are done in loops over large data, the user is better supported to providing recycled working arrays to the ExportValues(ref ..) function to get/set the next chunk of data in a much more memory efficient way.

    However, having a more convenient interface to System.Array will be of good use for all other scenarios.
  • +1 on the extension method approach.

    I actually expected that you comment on the naming and the possible performance issues. And I agree on both.

    1. .ToArray() should be ok, not too confusing.

    2. For memory management, I imaging .ToArray() to return a copy of the ILArray instead of a reference?! In that case, I would consider any copy under my own responsibility. Of course, if someone creates lots of System.Arrays the memory pressure grows and will have negative performance impact. But mostly the heavy computations are done either by an external library or by using ILNumerics, and just a nice way to pass arrays forward/backward is needed. At least in my code, I never mix ILNumerics and "pure" platform code.

    One option might be to create a scope for external code, as you do for ILInArray/ILOutArray/...? So instead of
    a = ILArray.ToArray();
    MyFunction(a);

    one could also have
    using (a = ILArray.ToManagedArray()) {
    MyFunction(a);
    }

    which then gives a reference to an internal ILArray (similar to GetArrayForRead/Write).

    P.S. The scope thing just came to my thoughts. Maybe I wrong on that end.
  • with only a slight modification, your scoping scheme would work:
    using System;
    using System.Numerics;
    using ILNumerics;
     
    public static class yourComputationClass : ILMath {
     
    public static void yourFunc(ILInArray<complex> A) {
    using (ILScope.Enter(A)) {
    // convert ILNumerics.complex -> System.Numerics.Complex
    ILArray<Complex> MSComplex = toComplex(A);
    Complex[] a = MSComplex.GetArrayForWrite();
     
    // do some processing here with the Complex[] array a
    myFunction(a);
    // ...
    // ...
     
    // when leaving this scope, the array will be recycled
    // hence make sure, not to reference it after that point!
    }
    }
     
    // Simple conversion function from ILNumerics.complex -> System.Numerics.Complex
    // An improved version would have to be provided by ILNumerics ..
    public static ILRetArray<Complex> toComplex(ILInArray<complex> A) {
    using (ILScope.Enter(A)) {
    ILArray<Complex> ret = zeros<Complex>(A.S);
    // skip parameter checking for simplicity ..
    complex[] AArr = A.GetArrayForRead();
    Complex[] CArr = ret.GetArrayForWrite();
    for (int i = 0; i < ret.S.NumberOfElements; i++) {
    complex a = AArr[i];
    CArr[i] = new Complex(a.real, a.imag);
    }
    return ret;
    }
    }
    }


    That way all System.Arrays (Complex[] or complex[]) are always under control of the ILNumerics memory management. The toComplex() function can be done much more efficiently and should be provided next to existing conversion functions within ILNumerics. (Possibly, again, with a more unique name, like: "toMSComplex()" or so)

    The scheme can be extended to return the results of the myFunction(a) step easily.

    &Edit: made the type of the input array A -> ILInArray<complex> according to our own function rules ;)
  • Meanwhile I have been exploring "complex" vs. "Complex" a little more.

    1. In general, the scoping concept above works pretty well. It would be nice to have an optimized version of the conversion functions in the library.

    2. I found one issue using your "simple" conversion function as an extension method. Consider the following signature:
    public static ILRetArray<Complex> ToMSComplex(this ILInArray<complex> A) { ... }

    It defines an extension method which only applies to ILInArray, not to any other ILArray-based type. In this case, you cannot use the method together with ILMath.Check() or its return. Both of the following does obviously not work:
    ILArray<Complex> data = ILMath.check(inData).ToMSComplex();
    ILArray<complex> data = ILMath.check(inData);
    ILArray<Complex> data2 = data .ToMSComplex();

    It means that you can not do any operation on the complex type with ILNumerics first, before converting to Complex for further processing, because you dont have ILInArray then anymore. We would need one override extension method for each ILArray-base type.

    3. I was thinking to replace Complex with your complex type in my code whereever possible and only use Complex where really required, i.e. when calling external code (as mentioned before). However, your complex type does not implement the generic IEquatable interface (in contrast to Complex) and therefore can not be used as a drop-in replacement in some cases.

    P.S. Sorry for long silence, I have been traveling a few weeks.
  • Hi twemg, nice to have you back!

    >1. In general, the scoping concept above works pretty well. It would be nice to have an optimized version of the conversion functions in the library.
    Agree. We will include this in the next release.

    >ILArray data = ILMath.check(inData).ToMSComplex();
    Right, if we would use extension methods, all 4 array types would need individual overloads. This would make sense, since all have to handle the memory differently. The overload for ILRetArray<complex> for example would dispose itself off immediately after the conversion. The one for ILArray<complex> does not.

    However, I tend to favor the functional form for simplicity reasons. It would IMO better integrate into the general conventions of ILNumerics of using functions for conversion between arrays within the library. Your example would be written:
    ILArray<Complex> data = toMSComplex(check(inData));


    The extension methods could be left to conversions into and out of ILNumerics:
    ILArray<complex> A = zeros<complex>(3,4);
    Complex[] msArray = A.ToMSComplex();


    But even those could be implemented via functions - possibly more simple and coherent? I count on votes for this decision.

    3. A very reasonable point! We will implement this for the next release. This can be an early release, but we should decide 2) first and include these conversions also.
  • I guess, conversion using functions means that they will live in the ILMath namespace? Or do you want to create an isolated namespace solely for conversion functions? For me it doesnt make much difference whether its a function or an extension method. There is one advantage of the extension methods, though. They only show up (in Intellisense) for types they actually apply for and are somewhat hidden otherwise. For functions in ILMath you only find them compatible with your type once you fully typed them in.

    For me there is still one big question:
    The native Complex type is not fully supported by ILNumerics, but you chose to have your own complex type for good reasons. Should their be a prominent conversion to ILArray<Complex> then? Or would it be better/nicer to provide a direct conversion from ILArray<complex> to Complex[] as you imply with your extension method above (into and out of ILNumerics)? My vote goes for a direct conversion support, be it as a function or extension method. The use cases for ILArray<Complex> are rare and the two-step conversion kind of promotes Complex and ILArray being used together.

    P.S. I'd be happy to beta test your releases, if you need feedback.
  • One good reason to keep our own ILNumerics.complex type turned out not to be one anymore: System.Numerics.Complex _does_ qualify for use in native functions like LAPACK. So the most important concern left is downward compatibility. Our users used ILNumerics.complex long before System.Numerics.Complex showed up. And the .NET type does implement some edge cases differently/ not at all. For the long term, however, it seems not optimal to have two parallel implementations of the same type. We currently are investigating possible issues with removing ILNumerics.complex. Even if we remove it at some point, it will not be soon and only after making sure, the transition will be as easy as adding an alias from ILNumerics.complex to the Microsoft type.

    I think you are right, we should concentrate on simplicity of conversion for now. I implemented two extension methods: Complex[].ToILArray() and ILArray<complex>.ToMSComplex(). Some overloads exist in order to handle some memory management. The methods work on all complex array variables (regardless if in/out/ret or local array).

    Thank you very much for your offer regarding beta testing! I've sent you the release candidate by pm.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID