3

I'm trying to use catboost to predict for one array of floats.

In the documentation for CalcModelPredictionSingle it takes as param "floatFeatures - array of float features": https://github.com/catboost/catboost/blob/master/catboost/libs/model_interface/c_api.h#L175

However when I try to pass an array of floats, I get this error:

Cannot use type []*_Ctype_float as *_Ctype_float in assignment.

Indicating it's expecting a single float. Am I using the wrong function?

I am using cgo and this is part of my code:

```
floats := []float32{}
//gets populated

floatsC := make([]*C.float, len(floats))
for i, v := range floats {
    floatsC[i] = (*C.float)(&v)
}

if !C.CalcModelPredictionSingle(
    model.Handle,
    ([]*C.float)(floatsC),
    ...
) {
    return
}
rustyx
  • 80,671
  • 25
  • 200
  • 267
Gargameli
  • 85
  • 1
  • 2
  • 8
  • 2
    in C pointer to a float is indistinguishable from pointer to the first element of an array of floats (after it is passed to a function), the issue must be on the go side... – Grady Player Oct 19 '21 at 15:45
  • 1
    @GradyPlayer Indeed, it is the fact that (as a parameter anyway) C conflates "array N of T" with "pointer to T", while Go doesn't, that is the problem here. As rustyx answered the trick is to use a Go array-or-slice and get a pointer to the first element, which is just manually expressing what a C compiler does at the caller. – torek Oct 19 '21 at 16:48

1 Answers1

3

The API is expecting an array of floats, but []*C.float that you're trying to make is an array of pointers-to-floats. Those are incompatible types, which is exactly what the compiler is telling.

The good news is none of that is necessary as a Go []float32 is layout-compatible with a C float[] so you can pass your Go slice directly to the C function as a pointer to its first element.

floats := []float32{}
//gets populated
    
if !C.CalcModelPredictionSingle(
    model.Handle,
    (*C.float)(&floats[0]), // pass the pointer to the first slice element
    C.size_t(len(floats)),  // pass the slice length
    ...
) {
    return
}

Note that in C float[] and *float are the same thing.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • thanks a lot for your response. I'm very new to Catboost. Could you explain to me why passing only the first element would suffice? Isn't the rest of the array ignored? – Gargameli Oct 19 '21 at 16:54
  • 2
    @Gargameli in C, when you call a function it doesn't pass in a whole array of anything, and C doesn't know anything about the length of an array, it is only expressed as the address of the first element. When you pass an array to a function it is said to "degenerate" to a pointer. – Grady Player Oct 19 '21 at 18:50
  • 1
    @GradyPlayer Thank you very much, you saved me a lot of headache. I was very thrown off by the examples. – Gargameli Oct 20 '21 at 14:54