5
$\begingroup$

I am trying to load a function written in C++ using LibaryFunctionLoad. Doing so, I have encountered an issue I believe to be a bug (I wanted to ask here first in case I'm missing something obvious):

Take e.g. the following C/C++ function:

EXTERN_C DLLEXPORT int inc(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res)
{
    MArgument_setInteger(Res, MArgument_getInteger(Args[0]) + 1);

    return LIBRARY_NO_ERROR;
}

Load it in MMA:

inc = LibraryFunctionLoad[NotebookDirectory[] <> "inc.dll", "inc", {_Integer}, _Integer];

This works mostly as expected:

inc[5]
(* 6 *)

inc[2^63]
(* Error, should be machine-sized integer *)

inc[2^63-1]
(* -9223372036854775808 *)

% == -2^63
(* True *)   

inc[-2^63+1]
(* -9223372036854775806 *)

However:

inc[-2^63]
(* Error, should be machine-sized integer *)

As you can see, it seems as if the bound check for machine-sized integers is off by one on the negative end. Is my observation correct or am I missing something? What speaks for this interpretation is the fact that inc[2^63-1] correctly returns -2^63 but this returned value can not be passed back to the function.

Update

I have received the following reply from Wolfram support:

Yes, this is a slightly unfortunate consequence of the discrepancy between the machine integer range in C and in WL. Specifically, -2^63 is a machine integer in C, but is not Developer`MachineIntegerQ.

The reasons for this design decision go far back.

The actual machine integer -2^63 is excluded from the definition of "machine integer in WL" even though it is one, because that allows an optimization -- don't need to check for packing/unpacking when negating a machine integer matrix.

I will try to find the easiest workaround for this issue and will update the post once I found one.

$\endgroup$
  • $\begingroup$ Probably this Developer`$MaxMachineInteger $\endgroup$ – halirutan Dec 17 '17 at 17:08
  • 1
    $\begingroup$ @halirutan what do you want to say with that? Normally, integer bounds for signed integers are $-2^{n-1},...,2^{n-1}-1$. $\endgroup$ – Lukas Lang Dec 17 '17 at 17:19
  • $\begingroup$ This does work: RawArray["Integer64", {-2^63}] (for raw arrays it would seem to be more important to accurately represent the full range). $\endgroup$ – Szabolcs Dec 17 '17 at 18:03
  • $\begingroup$ Interestingly, it is still possible to return a packed array containing -2^63 from LibraryLink. Negating this packed array will trigger unpacking. I guess not all packed arrays are the same. $\endgroup$ – Szabolcs Dec 25 '17 at 14:21
4
$\begingroup$

My comment was only a pointer to the bound in Mathematica. I too believe that the bound check is weird. Let me give a simple example that probably makes it a bit clearer than the ones from Mathe172

dec = Compile[{{i, _Integer, 0}},
   i - 1,
   CompilationTarget -> "C"
   ];

When we decrement the smallest possible integer, the sign should flip and we should end with the largest possible integer. This gives us a warning and falls back to Kernel evaluation:

Mathematica graphics

Therefore, the smallest possible machine integer must be larger:

dec[-2^63 + 1]
(* -9223372036854775808 *)

However, note that we end up with the negative number -2^63 which was claimed before to not be a machine integer. Therefore, I believe the bound-check is off as well.

One possible explanation is that not all integer representations are asymmetric like the twos-complement. In fact, all other ones I know are symmetric (ones-complement, sign-representation). Probably the bound-check is a compromise to work on all machines.

$\endgroup$
  • $\begingroup$ This is a bit similar to how it is possible to return Infinity from a LibraryFunction, but not pass it to it. If the Infinity is in a packed array, it will cause weird behaviour unless the array is unpacked first. $\endgroup$ – Szabolcs Dec 17 '17 at 17:54
  • $\begingroup$ Thanks a lot for your answer! I have updated the main question with a reply from Wolfram support - apparently, the reason for the decision was really the symmetry of the integer representation $\endgroup$ – Lukas Lang Dec 24 '17 at 10:09
4
$\begingroup$

This is a long comment.

It could be a bug, but it could also be some weirdness in the handling of machine integers. I think the only thing you can do is contact Wolfram Support, and let us know what they said.

Mathematica's behaviour seems much too consistent for this to be a "bug" (i.e. something they overlooked).

Developer`MachineIntegerQ[-2^63]
(* False *)

Developer`PackedArrayQ[
 Developer`ToPackedArray[{-2^63 + 1}]
 ]
(* True *)

Developer`PackedArrayQ[
 Developer`ToPackedArray[{-2^63 + 1}] - 1
 ]
(* False *)

If I try to return this value from a LibraryLink library, the result also isn't a machine integer according to these functions.

However, if I try to return a single-element Integer array containing a value, then it is still treated as a packed array.

This very last finding is inconsistent with the rest and suggests a possible bug to me.


The LTemplate code I used for testing (for reference):

<< LTemplate`

SetDirectory@CreateDirectory[];

tem = LClass["Bounds", {
    LFun["lowest", {}, Integer],
    LFun["lowestArr", {}, {Integer, 1}]
    }];

code = "
  struct Bounds {

      mint lowest() { return (1L << 63); }

      mma::IntTensorRef lowestArr() {
        auto arr = mma::makeVector<mint>(1);
        arr[0] = (1L << 63);
        return arr;
    }
  };";
Export["Bounds.h", code, "String"];

CompileTemplate[tem]

LoadTemplate[tem]

obj = Make[Bounds];

obj@"lowest"[]
(* -9223372036854775808 *)

Developer`PackedArrayQ[obj@"lowestArr"[]]
(* True *)
$\endgroup$
  • 1
    $\begingroup$ Thanks a lot for your answer! I have updated the main question with a reply from Wolfram support - it seems that your conclusion was correct $\endgroup$ – Lukas Lang Dec 24 '17 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.