-1

I write methods for a c extension type:

static PyObject *
RawGraphState_apply_C_L(RawGraphState * self
                        , PyObject * args)
{
    npy_uint8 vop = 0xdeadbeef;
    npy_intp i;// = 0xdeadbeef;

    if(!PyArg_ParseTuple(args, "II", &i, &vop))
    {
        return NULL;
    }

    printf("i = %ld\n", i);

    if(vop >= 24)
    {
        PyErr_SetString(PyExc_ValueError, "vop index must be in [0, 23]");
        return NULL;
    }

    if(i >= self->length)
    {
        PyErr_SetString(PyExc_ValueError, "qbit index out of range");
        return NULL;
    }

    printf("mapping vop[%ld] %d,%d -> %d\n", i, vop, self->vops[i], vop_lookup_table[vop][self->vops[i]]);
    self->vops[i] = vop_lookup_table[vop][self->vops[i]];

    Py_RETURN_NONE;

}

However this does not read the first argument correctly. It either defaults to 0 or to a huge number (depending on wheter I call the method in pytest or using ipython):

In [1]: from pyqcs.graph.backend.raw_state import RawGraphState                                                                        
^[[A
In [2]: g = RawGraphState(2)                                                                                                           

In [3]: g.apply_C_L(1, 0)                                                                                                              
i = 140200617443328
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-57081093fbb3> in <module>
----> 1 g.apply_C_L(1, 0)

ValueError: qbit index out of range

What am I doing wrong here?

--

You can find the code here:

https://github.com/daknuett/PyQCS/blob/graph_simulation/src/pyqcs/graph/backend/raw_state.c

starting at line 300.

LittleByBlue
  • 436
  • 9
  • 18

1 Answers1

1

The format code I expects to be passed a pointer to an unsigned int. Not an npy_uint8 or an npy_intp. An unsigned int and only an unsigned int. An 8 bit uint like vop is is definitely the wrong size, as an attempt to write to it as if it were a normal unsigned int will likely overwrite some other data. A npy_intp might or might not be the right size, but since it could be wrong, don't use it.

For the first argument you want either b or B, which is an unsigned char (8 bits on pretty much every platform). Read the documentation for the difference. For the second argument would probably want to use K for an unsigned long long, pass it an unsigned long long (which should be big enough...), and then convert that to npy_intp checking for overflow yourself. Alternatively you might use O then call PyLong_AsVoidPtr on that to get the number to C.

As an aside: npy_uint8 vop = 0xdeadbeef; should probably generate a warning since the number won't fit into 8 bits.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • Ah. It seems like I underestimated the importance to exactly match the actual data type size. It worked. Thanks. – LittleByBlue Nov 06 '19 at 15:03
  • The trouble is `PyArg_Parse` is a C "vararg" functions - they don't have any information about what data types are passed to them except for what you tell them. Therefore, all the helpful compiler errors and warnings that'd normally alert you to this can't work. – DavidW Nov 06 '19 at 15:18
  • To be fair I thought using a similar data type (int or long) would be enough. Sounds kind of stupid when you speak it out loud. – LittleByBlue Nov 06 '19 at 15:25