lightgbm_R.cpp 45 KB
Newer Older
1
2
3
4
/*!
 * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
5
6

#include "lightgbm_R.h"
Guolin Ke's avatar
Guolin Ke committed
7

8
9
10
11
12
13
14
#include <LightGBM/utils/common.h>
#include <LightGBM/utils/log.h>
#include <LightGBM/utils/openmp_wrapper.h>
#include <LightGBM/utils/text_reader.h>

#include <R_ext/Rdynload.h>

15
16
17
18
#define R_NO_REMAP
#define R_USE_C99_IN_CXX
#include <R_ext/Error.h>

19
20
#include <string>
#include <cstdio>
21
#include <cstdlib>
22
23
24
25
#include <cstring>
#include <memory>
#include <utility>
#include <vector>
26
#include <algorithm>
27

Guolin Ke's avatar
Guolin Ke committed
28
29
#define COL_MAJOR (0)

30
31
32
33
34
35
#define MAX_LENGTH_ERR_MSG 1024
char R_errmsg_buffer[MAX_LENGTH_ERR_MSG];
struct LGBM_R_ErrorClass { SEXP cont_token; };
void LGBM_R_save_exception_msg(const std::exception &err);
void LGBM_R_save_exception_msg(const std::string &err);

Guolin Ke's avatar
Guolin Ke committed
36
37
38
#define R_API_BEGIN() \
  try {
#define R_API_END() } \
39
40
41
42
  catch(LGBM_R_ErrorClass &cont) { R_ContinueUnwind(cont.cont_token); } \
  catch(std::exception& ex) { LGBM_R_save_exception_msg(ex); } \
  catch(std::string& ex) { LGBM_R_save_exception_msg(ex); } \
  catch(...) { Rf_error("unknown exception"); } \
43
  Rf_error("%s", R_errmsg_buffer); \
44
  return R_NilValue; /* <- won't be reached */
Guolin Ke's avatar
Guolin Ke committed
45
46
47

#define CHECK_CALL(x) \
  if ((x) != 0) { \
48
    throw std::runtime_error(LGBM_GetLastError()); \
Guolin Ke's avatar
Guolin Ke committed
49
50
  }

51
52
53
54
55
56
57
58
59
60
61
62
63
64
// These are helper functions to allow doing a stack unwind
// after an R allocation error, which would trigger a long jump.
void LGBM_R_save_exception_msg(const std::exception &err) {
  std::snprintf(R_errmsg_buffer, MAX_LENGTH_ERR_MSG, "%s\n", err.what());
}

void LGBM_R_save_exception_msg(const std::string &err) {
  std::snprintf(R_errmsg_buffer, MAX_LENGTH_ERR_MSG, "%s\n", err.c_str());
}

SEXP wrapped_R_string(void *len) {
  return Rf_allocVector(STRSXP, *(reinterpret_cast<R_xlen_t*>(len)));
}

65
66
67
68
SEXP wrapped_R_raw(void *len) {
  return Rf_allocVector(RAWSXP, *(reinterpret_cast<R_xlen_t*>(len)));
}

69
70
71
72
73
74
75
76
SEXP wrapped_R_int(void *len) {
  return Rf_allocVector(INTSXP, *(reinterpret_cast<R_xlen_t*>(len)));
}

SEXP wrapped_R_real(void *len) {
  return Rf_allocVector(REALSXP, *(reinterpret_cast<R_xlen_t*>(len)));
}

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
SEXP wrapped_Rf_mkChar(void *txt) {
  return Rf_mkChar(reinterpret_cast<char*>(txt));
}

void throw_R_memerr(void *ptr_cont_token, Rboolean jump) {
  if (jump) {
    LGBM_R_ErrorClass err{*(reinterpret_cast<SEXP*>(ptr_cont_token))};
    throw err;
  }
}

SEXP safe_R_string(R_xlen_t len, SEXP *cont_token) {
  return R_UnwindProtect(wrapped_R_string, reinterpret_cast<void*>(&len), throw_R_memerr, cont_token, *cont_token);
}

92
93
94
95
SEXP safe_R_raw(R_xlen_t len, SEXP *cont_token) {
  return R_UnwindProtect(wrapped_R_raw, reinterpret_cast<void*>(&len), throw_R_memerr, cont_token, *cont_token);
}

96
97
98
99
100
101
102
103
SEXP safe_R_int(R_xlen_t len, SEXP *cont_token) {
  return R_UnwindProtect(wrapped_R_int, reinterpret_cast<void*>(&len), throw_R_memerr, cont_token, *cont_token);
}

SEXP safe_R_real(R_xlen_t len, SEXP *cont_token) {
  return R_UnwindProtect(wrapped_R_real, reinterpret_cast<void*>(&len), throw_R_memerr, cont_token, *cont_token);
}

104
105
106
107
SEXP safe_R_mkChar(char *txt, SEXP *cont_token) {
  return R_UnwindProtect(wrapped_Rf_mkChar, reinterpret_cast<void*>(txt), throw_R_memerr, cont_token, *cont_token);
}

108
109
using LightGBM::Common::Split;
using LightGBM::Log;
Guolin Ke's avatar
Guolin Ke committed
110

111
112
113
114
SEXP LGBM_HandleIsNull_R(SEXP handle) {
  return Rf_ScalarLogical(R_ExternalPtrAddr(handle) == NULL);
}

115
116
117
118
void _DatasetFinalizer(SEXP handle) {
  LGBM_DatasetFree_R(handle);
}

119
120
121
122
123
124
125
126
SEXP LGBM_NullBoosterHandleError_R() {
  Rf_error(
      "Attempting to use a Booster which no longer exists and/or cannot be restored. "
      "This can happen if you have called Booster$finalize() "
      "or if this Booster was saved through saveRDS() using 'serializable=FALSE'.");
  return R_NilValue;
}

127
128
void _AssertBoosterHandleNotNull(SEXP handle) {
  if (Rf_isNull(handle) || !R_ExternalPtrAddr(handle)) {
129
    LGBM_NullBoosterHandleError_R();
130
131
132
133
134
135
136
137
138
139
140
141
  }
}

void _AssertDatasetHandleNotNull(SEXP handle) {
  if (Rf_isNull(handle) || !R_ExternalPtrAddr(handle)) {
    Rf_error(
      "Attempting to use a Dataset which no longer exists. "
      "This can happen if you have called Dataset$finalize() or if this Dataset was saved with saveRDS(). "
      "To avoid this error in the future, use lgb.Dataset.save() or Dataset$save_binary() to save lightgbm Datasets.");
  }
}

142
143
SEXP LGBM_DatasetCreateFromFile_R(SEXP filename,
  SEXP parameters,
144
  SEXP reference) {
145
  R_API_BEGIN();
146
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
Guolin Ke's avatar
Guolin Ke committed
147
  DatasetHandle handle = nullptr;
148
149
150
151
  DatasetHandle ref = nullptr;
  if (!Rf_isNull(reference)) {
    ref = R_ExternalPtrAddr(reference);
  }
152
153
154
  const char* filename_ptr = CHAR(PROTECT(Rf_asChar(filename)));
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
  CHECK_CALL(LGBM_DatasetCreateFromFile(filename_ptr, parameters_ptr, ref, &handle));
155
  R_SetExternalPtrAddr(ret, handle);
156
  R_RegisterCFinalizerEx(ret, _DatasetFinalizer, TRUE);
157
  UNPROTECT(3);
158
  return ret;
159
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
160
161
}

162
163
164
SEXP LGBM_DatasetCreateFromCSC_R(SEXP indptr,
  SEXP indices,
  SEXP data,
165
166
167
  SEXP num_indptr,
  SEXP nelem,
  SEXP num_row,
168
  SEXP parameters,
169
  SEXP reference) {
170
  R_API_BEGIN();
171
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
172
173
174
  const int* p_indptr = INTEGER(indptr);
  const int* p_indices = INTEGER(indices);
  const double* p_data = REAL(data);
175
176
177
  int64_t nindptr = static_cast<int64_t>(Rf_asInteger(num_indptr));
  int64_t ndata = static_cast<int64_t>(Rf_asInteger(nelem));
  int64_t nrow = static_cast<int64_t>(Rf_asInteger(num_row));
178
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
Guolin Ke's avatar
Guolin Ke committed
179
  DatasetHandle handle = nullptr;
180
181
182
183
  DatasetHandle ref = nullptr;
  if (!Rf_isNull(reference)) {
    ref = R_ExternalPtrAddr(reference);
  }
Guolin Ke's avatar
Guolin Ke committed
184
185
  CHECK_CALL(LGBM_DatasetCreateFromCSC(p_indptr, C_API_DTYPE_INT32, p_indices,
    p_data, C_API_DTYPE_FLOAT64, nindptr, ndata,
186
    nrow, parameters_ptr, ref, &handle));
187
  R_SetExternalPtrAddr(ret, handle);
188
  R_RegisterCFinalizerEx(ret, _DatasetFinalizer, TRUE);
189
  UNPROTECT(2);
190
  return ret;
191
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
192
193
}

194
SEXP LGBM_DatasetCreateFromMat_R(SEXP data,
195
196
  SEXP num_row,
  SEXP num_col,
197
  SEXP parameters,
198
  SEXP reference) {
199
  R_API_BEGIN();
200
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
201
202
  int32_t nrow = static_cast<int32_t>(Rf_asInteger(num_row));
  int32_t ncol = static_cast<int32_t>(Rf_asInteger(num_col));
203
  double* p_mat = REAL(data);
204
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
Guolin Ke's avatar
Guolin Ke committed
205
  DatasetHandle handle = nullptr;
206
207
208
209
  DatasetHandle ref = nullptr;
  if (!Rf_isNull(reference)) {
    ref = R_ExternalPtrAddr(reference);
  }
Guolin Ke's avatar
Guolin Ke committed
210
  CHECK_CALL(LGBM_DatasetCreateFromMat(p_mat, C_API_DTYPE_FLOAT64, nrow, ncol, COL_MAJOR,
211
    parameters_ptr, ref, &handle));
212
  R_SetExternalPtrAddr(ret, handle);
213
  R_RegisterCFinalizerEx(ret, _DatasetFinalizer, TRUE);
214
  UNPROTECT(2);
215
  return ret;
216
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
217
218
}

219
SEXP LGBM_DatasetGetSubset_R(SEXP handle,
220
  SEXP used_row_indices,
221
  SEXP len_used_row_indices,
222
  SEXP parameters) {
223
  R_API_BEGIN();
224
  _AssertDatasetHandleNotNull(handle);
225
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
226
227
  int32_t len = static_cast<int32_t>(Rf_asInteger(len_used_row_indices));
  std::vector<int32_t> idxvec(len);
228
  // convert from one-based to zero-based index
229
  const int *used_row_indices_ = INTEGER(used_row_indices);
230
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024)
231
  for (int32_t i = 0; i < len; ++i) {
232
    idxvec[i] = static_cast<int32_t>(used_row_indices_[i] - 1);
Guolin Ke's avatar
Guolin Ke committed
233
  }
234
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
Guolin Ke's avatar
Guolin Ke committed
235
  DatasetHandle res = nullptr;
236
  CHECK_CALL(LGBM_DatasetGetSubset(R_ExternalPtrAddr(handle),
237
    idxvec.data(), len, parameters_ptr,
Guolin Ke's avatar
Guolin Ke committed
238
    &res));
239
  R_SetExternalPtrAddr(ret, res);
240
  R_RegisterCFinalizerEx(ret, _DatasetFinalizer, TRUE);
241
  UNPROTECT(2);
242
  return ret;
243
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
244
245
}

246
SEXP LGBM_DatasetSetFeatureNames_R(SEXP handle,
247
  SEXP feature_names) {
248
  R_API_BEGIN();
249
  _AssertDatasetHandleNotNull(handle);
250
  auto vec_names = Split(CHAR(PROTECT(Rf_asChar(feature_names))), '\t');
Guolin Ke's avatar
Guolin Ke committed
251
252
253
254
255
  std::vector<const char*> vec_sptr;
  int len = static_cast<int>(vec_names.size());
  for (int i = 0; i < len; ++i) {
    vec_sptr.push_back(vec_names[i].c_str());
  }
256
  CHECK_CALL(LGBM_DatasetSetFeatureNames(R_ExternalPtrAddr(handle),
Guolin Ke's avatar
Guolin Ke committed
257
    vec_sptr.data(), len));
258
259
  UNPROTECT(1);
  return R_NilValue;
260
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
261
262
}

263
SEXP LGBM_DatasetGetFeatureNames_R(SEXP handle) {
264
265
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
266
  _AssertDatasetHandleNotNull(handle);
267
  SEXP feature_names;
Guolin Ke's avatar
Guolin Ke committed
268
  int len = 0;
269
  CHECK_CALL(LGBM_DatasetGetNumFeature(R_ExternalPtrAddr(handle), &len));
270
  const size_t reserved_string_size = 256;
Guolin Ke's avatar
Guolin Ke committed
271
272
273
  std::vector<std::vector<char>> names(len);
  std::vector<char*> ptr_names(len);
  for (int i = 0; i < len; ++i) {
274
    names[i].resize(reserved_string_size);
Guolin Ke's avatar
Guolin Ke committed
275
276
277
    ptr_names[i] = names[i].data();
  }
  int out_len;
278
279
280
  size_t required_string_size;
  CHECK_CALL(
    LGBM_DatasetGetFeatureNames(
281
      R_ExternalPtrAddr(handle),
282
283
284
      len, &out_len,
      reserved_string_size, &required_string_size,
      ptr_names.data()));
285
286
287
288
289
290
291
292
293
  // if any feature names were larger than allocated size,
  // allow for a larger size and try again
  if (required_string_size > reserved_string_size) {
    for (int i = 0; i < len; ++i) {
      names[i].resize(required_string_size);
      ptr_names[i] = names[i].data();
    }
    CHECK_CALL(
      LGBM_DatasetGetFeatureNames(
294
        R_ExternalPtrAddr(handle),
295
296
297
298
299
300
        len,
        &out_len,
        required_string_size,
        &required_string_size,
        ptr_names.data()));
  }
Nikita Titov's avatar
Nikita Titov committed
301
  CHECK_EQ(len, out_len);
302
  feature_names = PROTECT(safe_R_string(static_cast<R_xlen_t>(len), &cont_token));
303
  for (int i = 0; i < len; ++i) {
304
    SET_STRING_ELT(feature_names, i, safe_R_mkChar(ptr_names[i], &cont_token));
305
  }
306
  UNPROTECT(2);
307
  return feature_names;
308
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
309
310
}

311
SEXP LGBM_DatasetSaveBinary_R(SEXP handle,
312
  SEXP filename) {
Guolin Ke's avatar
Guolin Ke committed
313
  R_API_BEGIN();
314
  _AssertDatasetHandleNotNull(handle);
315
  const char* filename_ptr = CHAR(PROTECT(Rf_asChar(filename)));
316
  CHECK_CALL(LGBM_DatasetSaveBinary(R_ExternalPtrAddr(handle),
317
318
319
    filename_ptr));
  UNPROTECT(1);
  return R_NilValue;
320
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
321
322
}

323
SEXP LGBM_DatasetFree_R(SEXP handle) {
Guolin Ke's avatar
Guolin Ke committed
324
  R_API_BEGIN();
325
  if (!Rf_isNull(handle) && R_ExternalPtrAddr(handle)) {
326
327
    CHECK_CALL(LGBM_DatasetFree(R_ExternalPtrAddr(handle)));
    R_ClearExternalPtr(handle);
Guolin Ke's avatar
Guolin Ke committed
328
  }
329
  return R_NilValue;
330
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
331
332
}

333
SEXP LGBM_DatasetSetField_R(SEXP handle,
334
  SEXP field_name,
335
  SEXP field_data,
336
  SEXP num_element) {
337
  R_API_BEGIN();
338
  _AssertDatasetHandleNotNull(handle);
339
  int len = Rf_asInteger(num_element);
340
  const char* name = CHAR(PROTECT(Rf_asChar(field_name)));
Guolin Ke's avatar
Guolin Ke committed
341
342
  if (!strcmp("group", name) || !strcmp("query", name)) {
    std::vector<int32_t> vec(len);
343
    const int *field_data_ = INTEGER(field_data);
344
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
345
    for (int i = 0; i < len; ++i) {
346
      vec[i] = static_cast<int32_t>(field_data_[i]);
Guolin Ke's avatar
Guolin Ke committed
347
    }
348
    CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_INT32));
349
  } else if (!strcmp("init_score", name)) {
350
    CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64));
Guolin Ke's avatar
Guolin Ke committed
351
352
  } else {
    std::vector<float> vec(len);
353
    const double *field_data_ = REAL(field_data);
354
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
355
    for (int i = 0; i < len; ++i) {
356
      vec[i] = static_cast<float>(field_data_[i]);
Guolin Ke's avatar
Guolin Ke committed
357
    }
358
    CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_FLOAT32));
Guolin Ke's avatar
Guolin Ke committed
359
  }
360
361
  UNPROTECT(1);
  return R_NilValue;
362
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
363
364
}

365
SEXP LGBM_DatasetGetField_R(SEXP handle,
366
  SEXP field_name,
367
  SEXP field_data) {
368
  R_API_BEGIN();
369
  _AssertDatasetHandleNotNull(handle);
370
  const char* name = CHAR(PROTECT(Rf_asChar(field_name)));
Guolin Ke's avatar
Guolin Ke committed
371
372
373
  int out_len = 0;
  int out_type = 0;
  const void* res;
374
  CHECK_CALL(LGBM_DatasetGetField(R_ExternalPtrAddr(handle), name, &out_len, &res, &out_type));
Guolin Ke's avatar
Guolin Ke committed
375
376
377
  if (!strcmp("group", name) || !strcmp("query", name)) {
    auto p_data = reinterpret_cast<const int32_t*>(res);
    // convert from boundaries to size
378
    int *field_data_ = INTEGER(field_data);
379
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
380
    for (int i = 0; i < out_len - 1; ++i) {
381
      field_data_[i] = p_data[i + 1] - p_data[i];
Guolin Ke's avatar
Guolin Ke committed
382
    }
Guolin Ke's avatar
Guolin Ke committed
383
384
  } else if (!strcmp("init_score", name)) {
    auto p_data = reinterpret_cast<const double*>(res);
385
    double *field_data_ = REAL(field_data);
386
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
387
    for (int i = 0; i < out_len; ++i) {
388
      field_data_[i] = p_data[i];
Guolin Ke's avatar
Guolin Ke committed
389
    }
Guolin Ke's avatar
Guolin Ke committed
390
391
  } else {
    auto p_data = reinterpret_cast<const float*>(res);
392
    double *field_data_ = REAL(field_data);
393
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
394
    for (int i = 0; i < out_len; ++i) {
395
      field_data_[i] = p_data[i];
Guolin Ke's avatar
Guolin Ke committed
396
397
    }
  }
398
399
  UNPROTECT(1);
  return R_NilValue;
400
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
401
402
}

403
SEXP LGBM_DatasetGetFieldSize_R(SEXP handle,
404
  SEXP field_name,
405
  SEXP out) {
406
  R_API_BEGIN();
407
  _AssertDatasetHandleNotNull(handle);
408
  const char* name = CHAR(PROTECT(Rf_asChar(field_name)));
Guolin Ke's avatar
Guolin Ke committed
409
410
411
  int out_len = 0;
  int out_type = 0;
  const void* res;
412
  CHECK_CALL(LGBM_DatasetGetField(R_ExternalPtrAddr(handle), name, &out_len, &res, &out_type));
Guolin Ke's avatar
Guolin Ke committed
413
414
415
  if (!strcmp("group", name) || !strcmp("query", name)) {
    out_len -= 1;
  }
416
  INTEGER(out)[0] = out_len;
417
418
  UNPROTECT(1);
  return R_NilValue;
419
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
420
421
}

422
423
SEXP LGBM_DatasetUpdateParamChecking_R(SEXP old_params,
  SEXP new_params) {
424
  R_API_BEGIN();
425
426
427
428
429
  const char* old_params_ptr = CHAR(PROTECT(Rf_asChar(old_params)));
  const char* new_params_ptr = CHAR(PROTECT(Rf_asChar(new_params)));
  CHECK_CALL(LGBM_DatasetUpdateParamChecking(old_params_ptr, new_params_ptr));
  UNPROTECT(2);
  return R_NilValue;
430
  R_API_END();
431
432
}

433
SEXP LGBM_DatasetGetNumData_R(SEXP handle, SEXP out) {
Guolin Ke's avatar
Guolin Ke committed
434
  R_API_BEGIN();
435
  _AssertDatasetHandleNotNull(handle);
436
  int nrow;
437
  CHECK_CALL(LGBM_DatasetGetNumData(R_ExternalPtrAddr(handle), &nrow));
438
  INTEGER(out)[0] = nrow;
439
  return R_NilValue;
440
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
441
442
}

443
SEXP LGBM_DatasetGetNumFeature_R(SEXP handle,
444
  SEXP out) {
Guolin Ke's avatar
Guolin Ke committed
445
  R_API_BEGIN();
446
  _AssertDatasetHandleNotNull(handle);
447
  int nfeature;
448
  CHECK_CALL(LGBM_DatasetGetNumFeature(R_ExternalPtrAddr(handle), &nfeature));
449
  INTEGER(out)[0] = nfeature;
450
  return R_NilValue;
451
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
452
453
}

454
455
456
457
458
459
460
461
462
463
464
SEXP LGBM_DatasetGetFeatureNumBin_R(SEXP handle, SEXP feature_idx, SEXP out) {
  R_API_BEGIN();
  _AssertDatasetHandleNotNull(handle);
  int feature = Rf_asInteger(feature_idx);
  int nbins;
  CHECK_CALL(LGBM_DatasetGetFeatureNumBin(R_ExternalPtrAddr(handle), feature, &nbins));
  INTEGER(out)[0] = nbins;
  return R_NilValue;
  R_API_END();
}

Guolin Ke's avatar
Guolin Ke committed
465
466
// --- start Booster interfaces

467
468
469
470
void _BoosterFinalizer(SEXP handle) {
  LGBM_BoosterFree_R(handle);
}

471
SEXP LGBM_BoosterFree_R(SEXP handle) {
Guolin Ke's avatar
Guolin Ke committed
472
  R_API_BEGIN();
473
  if (!Rf_isNull(handle) && R_ExternalPtrAddr(handle)) {
474
475
    CHECK_CALL(LGBM_BoosterFree(R_ExternalPtrAddr(handle)));
    R_ClearExternalPtr(handle);
Guolin Ke's avatar
Guolin Ke committed
476
  }
477
  return R_NilValue;
478
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
479
480
}

481
482
SEXP LGBM_BoosterCreate_R(SEXP train_data,
  SEXP parameters) {
483
  R_API_BEGIN();
484
  _AssertDatasetHandleNotNull(train_data);
485
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
486
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
Guolin Ke's avatar
Guolin Ke committed
487
  BoosterHandle handle = nullptr;
488
  CHECK_CALL(LGBM_BoosterCreate(R_ExternalPtrAddr(train_data), parameters_ptr, &handle));
489
  R_SetExternalPtrAddr(ret, handle);
490
  R_RegisterCFinalizerEx(ret, _BoosterFinalizer, TRUE);
491
  UNPROTECT(2);
492
  return ret;
493
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
494
495
}

496
SEXP LGBM_BoosterCreateFromModelfile_R(SEXP filename) {
497
  R_API_BEGIN();
498
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
Guolin Ke's avatar
Guolin Ke committed
499
  int out_num_iterations = 0;
500
  const char* filename_ptr = CHAR(PROTECT(Rf_asChar(filename)));
Guolin Ke's avatar
Guolin Ke committed
501
  BoosterHandle handle = nullptr;
502
  CHECK_CALL(LGBM_BoosterCreateFromModelfile(filename_ptr, &out_num_iterations, &handle));
503
  R_SetExternalPtrAddr(ret, handle);
504
  R_RegisterCFinalizerEx(ret, _BoosterFinalizer, TRUE);
505
  UNPROTECT(2);
506
  return ret;
507
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
508
509
}

510
SEXP LGBM_BoosterLoadModelFromString_R(SEXP model_str) {
511
  R_API_BEGIN();
512
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
513
514
  SEXP temp = NULL;
  int n_protected = 1;
515
  int out_num_iterations = 0;
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  const char* model_str_ptr = nullptr;
  switch (TYPEOF(model_str)) {
    case RAWSXP: {
      model_str_ptr = reinterpret_cast<const char*>(RAW(model_str));
      break;
    }
    case CHARSXP: {
      model_str_ptr = reinterpret_cast<const char*>(CHAR(model_str));
      break;
    }
    case STRSXP: {
      temp = PROTECT(STRING_ELT(model_str, 0));
      n_protected++;
      model_str_ptr = reinterpret_cast<const char*>(CHAR(temp));
    }
  }
Guolin Ke's avatar
Guolin Ke committed
532
  BoosterHandle handle = nullptr;
533
  CHECK_CALL(LGBM_BoosterLoadModelFromString(model_str_ptr, &out_num_iterations, &handle));
534
  R_SetExternalPtrAddr(ret, handle);
535
  R_RegisterCFinalizerEx(ret, _BoosterFinalizer, TRUE);
536
  UNPROTECT(n_protected);
537
  return ret;
538
  R_API_END();
539
540
}

541
542
SEXP LGBM_BoosterMerge_R(SEXP handle,
  SEXP other_handle) {
Guolin Ke's avatar
Guolin Ke committed
543
  R_API_BEGIN();
544
545
  _AssertBoosterHandleNotNull(handle);
  _AssertBoosterHandleNotNull(other_handle);
546
  CHECK_CALL(LGBM_BoosterMerge(R_ExternalPtrAddr(handle), R_ExternalPtrAddr(other_handle)));
547
  return R_NilValue;
548
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
549
550
}

551
552
SEXP LGBM_BoosterAddValidData_R(SEXP handle,
  SEXP valid_data) {
Guolin Ke's avatar
Guolin Ke committed
553
  R_API_BEGIN();
554
555
  _AssertBoosterHandleNotNull(handle);
  _AssertDatasetHandleNotNull(valid_data);
556
  CHECK_CALL(LGBM_BoosterAddValidData(R_ExternalPtrAddr(handle), R_ExternalPtrAddr(valid_data)));
557
  return R_NilValue;
558
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
559
560
}

561
562
SEXP LGBM_BoosterResetTrainingData_R(SEXP handle,
  SEXP train_data) {
Guolin Ke's avatar
Guolin Ke committed
563
  R_API_BEGIN();
564
565
  _AssertBoosterHandleNotNull(handle);
  _AssertDatasetHandleNotNull(train_data);
566
  CHECK_CALL(LGBM_BoosterResetTrainingData(R_ExternalPtrAddr(handle), R_ExternalPtrAddr(train_data)));
567
  return R_NilValue;
568
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
569
570
}

571
SEXP LGBM_BoosterResetParameter_R(SEXP handle,
572
  SEXP parameters) {
Guolin Ke's avatar
Guolin Ke committed
573
  R_API_BEGIN();
574
  _AssertBoosterHandleNotNull(handle);
575
  const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters)));
576
577
578
  CHECK_CALL(LGBM_BoosterResetParameter(R_ExternalPtrAddr(handle), parameters_ptr));
  UNPROTECT(1);
  return R_NilValue;
579
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
580
581
}

582
SEXP LGBM_BoosterGetNumClasses_R(SEXP handle,
583
  SEXP out) {
Guolin Ke's avatar
Guolin Ke committed
584
  R_API_BEGIN();
585
  _AssertBoosterHandleNotNull(handle);
586
  int num_class;
587
  CHECK_CALL(LGBM_BoosterGetNumClasses(R_ExternalPtrAddr(handle), &num_class));
588
  INTEGER(out)[0] = num_class;
589
  return R_NilValue;
590
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
591
592
}

593
594
595
596
597
598
599
600
601
SEXP LGBM_BoosterGetNumFeature_R(SEXP handle) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int out = 0;
  CHECK_CALL(LGBM_BoosterGetNumFeature(R_ExternalPtrAddr(handle), &out));
  return Rf_ScalarInteger(out);
  R_API_END();
}

602
SEXP LGBM_BoosterUpdateOneIter_R(SEXP handle) {
Guolin Ke's avatar
Guolin Ke committed
603
  R_API_BEGIN();
604
  _AssertBoosterHandleNotNull(handle);
605
  int is_finished = 0;
606
  CHECK_CALL(LGBM_BoosterUpdateOneIter(R_ExternalPtrAddr(handle), &is_finished));
607
  return R_NilValue;
608
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
609
610
}

611
SEXP LGBM_BoosterUpdateOneIterCustom_R(SEXP handle,
612
613
  SEXP grad,
  SEXP hess,
614
  SEXP len) {
Guolin Ke's avatar
Guolin Ke committed
615
  R_API_BEGIN();
616
  _AssertBoosterHandleNotNull(handle);
617
  int is_finished = 0;
618
  int int_len = Rf_asInteger(len);
Guolin Ke's avatar
Guolin Ke committed
619
  std::vector<float> tgrad(int_len), thess(int_len);
620
621
  const double *grad_ = REAL(grad);
  const double *hess_ = REAL(hess);
622
#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (int_len >= 1024)
Guolin Ke's avatar
Guolin Ke committed
623
  for (int j = 0; j < int_len; ++j) {
624
625
    tgrad[j] = static_cast<float>(grad_[j]);
    thess[j] = static_cast<float>(hess_[j]);
Guolin Ke's avatar
Guolin Ke committed
626
  }
627
  CHECK_CALL(LGBM_BoosterUpdateOneIterCustom(R_ExternalPtrAddr(handle), tgrad.data(), thess.data(), &is_finished));
628
  return R_NilValue;
629
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
630
631
}

632
SEXP LGBM_BoosterRollbackOneIter_R(SEXP handle) {
Guolin Ke's avatar
Guolin Ke committed
633
  R_API_BEGIN();
634
  _AssertBoosterHandleNotNull(handle);
635
  CHECK_CALL(LGBM_BoosterRollbackOneIter(R_ExternalPtrAddr(handle)));
636
  return R_NilValue;
637
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
638
639
}

640
SEXP LGBM_BoosterGetCurrentIteration_R(SEXP handle,
641
  SEXP out) {
Guolin Ke's avatar
Guolin Ke committed
642
  R_API_BEGIN();
643
  _AssertBoosterHandleNotNull(handle);
644
  int out_iteration;
645
  CHECK_CALL(LGBM_BoosterGetCurrentIteration(R_ExternalPtrAddr(handle), &out_iteration));
646
  INTEGER(out)[0] = out_iteration;
647
  return R_NilValue;
648
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
649
650
}

651
SEXP LGBM_BoosterGetUpperBoundValue_R(SEXP handle,
652
  SEXP out_result) {
653
  R_API_BEGIN();
654
  _AssertBoosterHandleNotNull(handle);
655
  double* ptr_ret = REAL(out_result);
656
  CHECK_CALL(LGBM_BoosterGetUpperBoundValue(R_ExternalPtrAddr(handle), ptr_ret));
657
  return R_NilValue;
658
  R_API_END();
659
660
}

661
SEXP LGBM_BoosterGetLowerBoundValue_R(SEXP handle,
662
  SEXP out_result) {
663
  R_API_BEGIN();
664
  _AssertBoosterHandleNotNull(handle);
665
  double* ptr_ret = REAL(out_result);
666
  CHECK_CALL(LGBM_BoosterGetLowerBoundValue(R_ExternalPtrAddr(handle), ptr_ret));
667
  return R_NilValue;
668
  R_API_END();
669
670
}

671
SEXP LGBM_BoosterGetEvalNames_R(SEXP handle) {
672
673
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
674
  _AssertBoosterHandleNotNull(handle);
675
  SEXP eval_names;
Guolin Ke's avatar
Guolin Ke committed
676
  int len;
677
  CHECK_CALL(LGBM_BoosterGetEvalCounts(R_ExternalPtrAddr(handle), &len));
678
  const size_t reserved_string_size = 128;
Guolin Ke's avatar
Guolin Ke committed
679
680
681
  std::vector<std::vector<char>> names(len);
  std::vector<char*> ptr_names(len);
  for (int i = 0; i < len; ++i) {
682
    names[i].resize(reserved_string_size);
Guolin Ke's avatar
Guolin Ke committed
683
684
    ptr_names[i] = names[i].data();
  }
685

Guolin Ke's avatar
Guolin Ke committed
686
  int out_len;
687
688
689
  size_t required_string_size;
  CHECK_CALL(
    LGBM_BoosterGetEvalNames(
690
      R_ExternalPtrAddr(handle),
691
692
693
      len, &out_len,
      reserved_string_size, &required_string_size,
      ptr_names.data()));
694
695
696
697
698
699
700
701
702
  // if any eval names were larger than allocated size,
  // allow for a larger size and try again
  if (required_string_size > reserved_string_size) {
    for (int i = 0; i < len; ++i) {
      names[i].resize(required_string_size);
      ptr_names[i] = names[i].data();
    }
    CHECK_CALL(
      LGBM_BoosterGetEvalNames(
703
        R_ExternalPtrAddr(handle),
704
705
706
707
708
709
        len,
        &out_len,
        required_string_size,
        &required_string_size,
        ptr_names.data()));
  }
Nikita Titov's avatar
Nikita Titov committed
710
  CHECK_EQ(out_len, len);
711
  eval_names = PROTECT(safe_R_string(static_cast<R_xlen_t>(len), &cont_token));
712
  for (int i = 0; i < len; ++i) {
713
    SET_STRING_ELT(eval_names, i, safe_R_mkChar(ptr_names[i], &cont_token));
714
  }
715
  UNPROTECT(2);
716
  return eval_names;
717
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
718
719
}

720
SEXP LGBM_BoosterGetEval_R(SEXP handle,
721
  SEXP data_idx,
722
  SEXP out_result) {
Guolin Ke's avatar
Guolin Ke committed
723
  R_API_BEGIN();
724
  _AssertBoosterHandleNotNull(handle);
Guolin Ke's avatar
Guolin Ke committed
725
  int len;
726
  CHECK_CALL(LGBM_BoosterGetEvalCounts(R_ExternalPtrAddr(handle), &len));
727
  double* ptr_ret = REAL(out_result);
Guolin Ke's avatar
Guolin Ke committed
728
  int out_len;
729
  CHECK_CALL(LGBM_BoosterGetEval(R_ExternalPtrAddr(handle), Rf_asInteger(data_idx), &out_len, ptr_ret));
Nikita Titov's avatar
Nikita Titov committed
730
  CHECK_EQ(out_len, len);
731
  return R_NilValue;
732
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
733
734
}

735
SEXP LGBM_BoosterGetNumPredict_R(SEXP handle,
736
  SEXP data_idx,
737
  SEXP out) {
Guolin Ke's avatar
Guolin Ke committed
738
  R_API_BEGIN();
739
  _AssertBoosterHandleNotNull(handle);
Guolin Ke's avatar
Guolin Ke committed
740
  int64_t len;
741
  CHECK_CALL(LGBM_BoosterGetNumPredict(R_ExternalPtrAddr(handle), Rf_asInteger(data_idx), &len));
742
  INTEGER(out)[0] = static_cast<int>(len);
743
  return R_NilValue;
744
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
745
746
}

747
SEXP LGBM_BoosterGetPredict_R(SEXP handle,
748
  SEXP data_idx,
749
  SEXP out_result) {
Guolin Ke's avatar
Guolin Ke committed
750
  R_API_BEGIN();
751
  _AssertBoosterHandleNotNull(handle);
752
  double* ptr_ret = REAL(out_result);
Guolin Ke's avatar
Guolin Ke committed
753
  int64_t out_len;
754
  CHECK_CALL(LGBM_BoosterGetPredict(R_ExternalPtrAddr(handle), Rf_asInteger(data_idx), &out_len, ptr_ret));
755
  return R_NilValue;
756
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
757
758
}

759
int GetPredictType(SEXP is_rawscore, SEXP is_leafidx, SEXP is_predcontrib) {
Guolin Ke's avatar
Guolin Ke committed
760
  int pred_type = C_API_PREDICT_NORMAL;
761
  if (Rf_asInteger(is_rawscore)) {
Guolin Ke's avatar
Guolin Ke committed
762
763
    pred_type = C_API_PREDICT_RAW_SCORE;
  }
764
  if (Rf_asInteger(is_leafidx)) {
Guolin Ke's avatar
Guolin Ke committed
765
766
    pred_type = C_API_PREDICT_LEAF_INDEX;
  }
767
  if (Rf_asInteger(is_predcontrib)) {
768
769
    pred_type = C_API_PREDICT_CONTRIB;
  }
Guolin Ke's avatar
Guolin Ke committed
770
771
772
  return pred_type;
}

773
SEXP LGBM_BoosterPredictForFile_R(SEXP handle,
774
  SEXP data_filename,
775
776
777
778
779
780
  SEXP data_has_header,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
781
782
  SEXP parameter,
  SEXP result_filename) {
783
  R_API_BEGIN();
784
  _AssertBoosterHandleNotNull(handle);
785
786
787
  const char* data_filename_ptr = CHAR(PROTECT(Rf_asChar(data_filename)));
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  const char* result_filename_ptr = CHAR(PROTECT(Rf_asChar(result_filename)));
788
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
789
790
791
792
793
  CHECK_CALL(LGBM_BoosterPredictForFile(R_ExternalPtrAddr(handle), data_filename_ptr,
    Rf_asInteger(data_has_header), pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), parameter_ptr,
    result_filename_ptr));
  UNPROTECT(3);
  return R_NilValue;
794
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
795
796
}

797
SEXP LGBM_BoosterCalcNumPredict_R(SEXP handle,
798
799
800
801
802
803
  SEXP num_row,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
804
  SEXP out_len) {
Guolin Ke's avatar
Guolin Ke committed
805
  R_API_BEGIN();
806
  _AssertBoosterHandleNotNull(handle);
807
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
Guolin Ke's avatar
Guolin Ke committed
808
  int64_t len = 0;
809
  CHECK_CALL(LGBM_BoosterCalcNumPredict(R_ExternalPtrAddr(handle), Rf_asInteger(num_row),
810
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), &len));
811
  INTEGER(out_len)[0] = static_cast<int>(len);
812
  return R_NilValue;
813
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
814
815
}

816
SEXP LGBM_BoosterPredictForCSC_R(SEXP handle,
817
818
819
  SEXP indptr,
  SEXP indices,
  SEXP data,
820
821
822
823
824
825
826
827
  SEXP num_indptr,
  SEXP nelem,
  SEXP num_row,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
828
  SEXP parameter,
829
  SEXP out_result) {
830
  R_API_BEGIN();
831
  _AssertBoosterHandleNotNull(handle);
832
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
833
  const int* p_indptr = INTEGER(indptr);
834
  const int32_t* p_indices = reinterpret_cast<const int32_t*>(INTEGER(indices));
835
  const double* p_data = REAL(data);
836
837
838
  int64_t nindptr = static_cast<int64_t>(Rf_asInteger(num_indptr));
  int64_t ndata = static_cast<int64_t>(Rf_asInteger(nelem));
  int64_t nrow = static_cast<int64_t>(Rf_asInteger(num_row));
839
  double* ptr_ret = REAL(out_result);
Guolin Ke's avatar
Guolin Ke committed
840
  int64_t out_len;
841
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
842
  CHECK_CALL(LGBM_BoosterPredictForCSC(R_ExternalPtrAddr(handle),
Guolin Ke's avatar
Guolin Ke committed
843
844
    p_indptr, C_API_DTYPE_INT32, p_indices,
    p_data, C_API_DTYPE_FLOAT64, nindptr, ndata,
845
846
847
    nrow, pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), parameter_ptr, &out_len, ptr_ret));
  UNPROTECT(1);
  return R_NilValue;
848
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
849
850
}

851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
SEXP LGBM_BoosterPredictForCSR_R(SEXP handle,
  SEXP indptr,
  SEXP indices,
  SEXP data,
  SEXP ncols,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter,
  SEXP out_result) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  int64_t out_len;
  CHECK_CALL(LGBM_BoosterPredictForCSR(R_ExternalPtrAddr(handle),
    INTEGER(indptr), C_API_DTYPE_INT32, INTEGER(indices),
    REAL(data), C_API_DTYPE_FLOAT64,
    Rf_xlength(indptr), Rf_xlength(data), Rf_asInteger(ncols),
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    parameter_ptr, &out_len, REAL(out_result)));
  UNPROTECT(1);
  return R_NilValue;
  R_API_END();
}

SEXP LGBM_BoosterPredictForCSRSingleRow_R(SEXP handle,
  SEXP indices,
  SEXP data,
  SEXP ncols,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter,
  SEXP out_result) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  int nnz = static_cast<int>(Rf_xlength(data));
  const int indptr[] = {0, nnz};
  int64_t out_len;
  CHECK_CALL(LGBM_BoosterPredictForCSRSingleRow(R_ExternalPtrAddr(handle),
    indptr, C_API_DTYPE_INT32, INTEGER(indices),
    REAL(data), C_API_DTYPE_FLOAT64,
    2, nnz, Rf_asInteger(ncols),
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    parameter_ptr, &out_len, REAL(out_result)));
  UNPROTECT(1);
  return R_NilValue;
  R_API_END();
}

void LGBM_FastConfigFree_wrapped(SEXP handle) {
  LGBM_FastConfigFree(static_cast<FastConfigHandle*>(R_ExternalPtrAddr(handle)));
}

SEXP LGBM_BoosterPredictForCSRSingleRowFastInit_R(SEXP handle,
  SEXP ncols,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  FastConfigHandle out_fastConfig;
  CHECK_CALL(LGBM_BoosterPredictForCSRSingleRowFastInit(R_ExternalPtrAddr(handle),
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    C_API_DTYPE_FLOAT64, Rf_asInteger(ncols),
    parameter_ptr, &out_fastConfig));
  R_SetExternalPtrAddr(ret, out_fastConfig);
  R_RegisterCFinalizerEx(ret, LGBM_FastConfigFree_wrapped, TRUE);
  UNPROTECT(2);
  return ret;
  R_API_END();
}

SEXP LGBM_BoosterPredictForCSRSingleRowFast_R(SEXP handle_fastConfig,
  SEXP indices,
  SEXP data,
  SEXP out_result) {
  R_API_BEGIN();
  int nnz = static_cast<int>(Rf_xlength(data));
  const int indptr[] = {0, nnz};
  int64_t out_len;
  CHECK_CALL(LGBM_BoosterPredictForCSRSingleRowFast(R_ExternalPtrAddr(handle_fastConfig),
    indptr, C_API_DTYPE_INT32, INTEGER(indices),
    REAL(data),
    2, nnz,
    &out_len, REAL(out_result)));
  return R_NilValue;
  R_API_END();
}

954
SEXP LGBM_BoosterPredictForMat_R(SEXP handle,
955
  SEXP data,
956
957
958
959
960
961
962
  SEXP num_row,
  SEXP num_col,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
963
  SEXP parameter,
964
  SEXP out_result) {
965
  R_API_BEGIN();
966
  _AssertBoosterHandleNotNull(handle);
967
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
968
969
  int32_t nrow = static_cast<int32_t>(Rf_asInteger(num_row));
  int32_t ncol = static_cast<int32_t>(Rf_asInteger(num_col));
970
971
  const double* p_mat = REAL(data);
  double* ptr_ret = REAL(out_result);
972
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
Guolin Ke's avatar
Guolin Ke committed
973
  int64_t out_len;
974
  CHECK_CALL(LGBM_BoosterPredictForMat(R_ExternalPtrAddr(handle),
Guolin Ke's avatar
Guolin Ke committed
975
    p_mat, C_API_DTYPE_FLOAT64, nrow, ncol, COL_MAJOR,
976
977
978
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), parameter_ptr, &out_len, ptr_ret));
  UNPROTECT(1);
  return R_NilValue;
979
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
980
981
}

982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
struct SparseOutputPointers {
  void* indptr;
  int32_t* indices;
  void* data;
  int indptr_type;
  int data_type;
  SparseOutputPointers(void* indptr, int32_t* indices, void* data)
  : indptr(indptr), indices(indices), data(data) {}
};

void delete_SparseOutputPointers(SparseOutputPointers *ptr) {
  LGBM_BoosterFreePredictSparse(ptr->indptr, ptr->indices, ptr->data, C_API_DTYPE_INT32, C_API_DTYPE_FLOAT64);
  delete ptr;
}

SEXP LGBM_BoosterPredictSparseOutput_R(SEXP handle,
  SEXP indptr,
  SEXP indices,
  SEXP data,
  SEXP is_csr,
  SEXP nrows,
  SEXP ncols,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter) {
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  const char* out_names[] = {"indptr", "indices", "data", ""};
  SEXP out = PROTECT(Rf_mkNamed(VECSXP, out_names));
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));

  int64_t out_len[2];
  void *out_indptr;
  int32_t *out_indices;
  void *out_data;

  CHECK_CALL(LGBM_BoosterPredictSparseOutput(R_ExternalPtrAddr(handle),
    INTEGER(indptr), C_API_DTYPE_INT32, INTEGER(indices),
    REAL(data), C_API_DTYPE_FLOAT64,
    Rf_xlength(indptr), Rf_xlength(data),
    Rf_asLogical(is_csr)? Rf_asInteger(ncols) : Rf_asInteger(nrows),
    C_API_PREDICT_CONTRIB, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    parameter_ptr,
    Rf_asLogical(is_csr)? C_API_MATRIX_TYPE_CSR : C_API_MATRIX_TYPE_CSC,
    out_len, &out_indptr, &out_indices, &out_data));

  std::unique_ptr<SparseOutputPointers, decltype(&delete_SparseOutputPointers)> pointers_struct = {
    new SparseOutputPointers(
      out_indptr,
      out_indices,
      out_data),
    &delete_SparseOutputPointers
  };

  SEXP out_indptr_R = safe_R_int(out_len[1], &cont_token);
  SET_VECTOR_ELT(out, 0, out_indptr_R);
  SEXP out_indices_R = safe_R_int(out_len[0], &cont_token);
  SET_VECTOR_ELT(out, 1, out_indices_R);
  SEXP out_data_R = safe_R_real(out_len[0], &cont_token);
  SET_VECTOR_ELT(out, 2, out_data_R);
  std::memcpy(INTEGER(out_indptr_R), out_indptr, out_len[1]*sizeof(int));
  std::memcpy(INTEGER(out_indices_R), out_indices, out_len[0]*sizeof(int));
  std::memcpy(REAL(out_data_R), out_data, out_len[0]*sizeof(double));

  UNPROTECT(3);
  return out;
  R_API_END();
}

1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
SEXP LGBM_BoosterPredictForMatSingleRow_R(SEXP handle,
  SEXP data,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter,
  SEXP out_result) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  double* ptr_ret = REAL(out_result);
  int64_t out_len;
  CHECK_CALL(LGBM_BoosterPredictForMatSingleRow(R_ExternalPtrAddr(handle),
    REAL(data), C_API_DTYPE_FLOAT64, Rf_xlength(data), 1,
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    parameter_ptr, &out_len, ptr_ret));
  UNPROTECT(1);
  return R_NilValue;
  R_API_END();
}

SEXP LGBM_BoosterPredictForMatSingleRowFastInit_R(SEXP handle,
  SEXP ncols,
  SEXP is_rawscore,
  SEXP is_leafidx,
  SEXP is_predcontrib,
  SEXP start_iteration,
  SEXP num_iteration,
  SEXP parameter) {
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
  SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue));
  const char* parameter_ptr = CHAR(PROTECT(Rf_asChar(parameter)));
  FastConfigHandle out_fastConfig;
  CHECK_CALL(LGBM_BoosterPredictForMatSingleRowFastInit(R_ExternalPtrAddr(handle),
    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration),
    C_API_DTYPE_FLOAT64, Rf_asInteger(ncols),
    parameter_ptr, &out_fastConfig));
  R_SetExternalPtrAddr(ret, out_fastConfig);
  R_RegisterCFinalizerEx(ret, LGBM_FastConfigFree_wrapped, TRUE);
  UNPROTECT(2);
  return ret;
  R_API_END();
}

SEXP LGBM_BoosterPredictForMatSingleRowFast_R(SEXP handle_fastConfig,
  SEXP data,
  SEXP out_result) {
  R_API_BEGIN();
  int64_t out_len;
  CHECK_CALL(LGBM_BoosterPredictForMatSingleRowFast(R_ExternalPtrAddr(handle_fastConfig),
    REAL(data), &out_len, REAL(out_result)));
  return R_NilValue;
  R_API_END();
}

1112
SEXP LGBM_BoosterSaveModel_R(SEXP handle,
1113
1114
  SEXP num_iteration,
  SEXP feature_importance_type,
1115
  SEXP filename) {
Guolin Ke's avatar
Guolin Ke committed
1116
  R_API_BEGIN();
1117
  _AssertBoosterHandleNotNull(handle);
1118
  const char* filename_ptr = CHAR(PROTECT(Rf_asChar(filename)));
1119
1120
1121
  CHECK_CALL(LGBM_BoosterSaveModel(R_ExternalPtrAddr(handle), 0, Rf_asInteger(num_iteration), Rf_asInteger(feature_importance_type), filename_ptr));
  UNPROTECT(1);
  return R_NilValue;
1122
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
1123
1124
}

1125
SEXP LGBM_BoosterSaveModelToString_R(SEXP handle,
1126
  SEXP num_iteration,
1127
  SEXP feature_importance_type) {
1128
1129
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
1130
  _AssertBoosterHandleNotNull(handle);
1131
  int64_t out_len = 0;
1132
  int64_t buf_len = 1024 * 1024;
1133
1134
  int num_iter = Rf_asInteger(num_iteration);
  int importance_type = Rf_asInteger(feature_importance_type);
1135
  std::vector<char> inner_char_buf(buf_len);
1136
  CHECK_CALL(LGBM_BoosterSaveModelToString(R_ExternalPtrAddr(handle), 0, num_iter, importance_type, buf_len, &out_len, inner_char_buf.data()));
1137
1138
  SEXP model_str = PROTECT(safe_R_raw(out_len, &cont_token));
  // if the model string was larger than the initial buffer, call the function again, writing directly to the R object
1139
  if (out_len > buf_len) {
1140
1141
1142
    CHECK_CALL(LGBM_BoosterSaveModelToString(R_ExternalPtrAddr(handle), 0, num_iter, importance_type, out_len, &out_len, reinterpret_cast<char*>(RAW(model_str))));
  } else {
    std::copy(inner_char_buf.begin(), inner_char_buf.begin() + out_len, reinterpret_cast<char*>(RAW(model_str)));
1143
  }
1144
  UNPROTECT(2);
1145
  return model_str;
1146
  R_API_END();
1147
1148
}

1149
SEXP LGBM_BoosterDumpModel_R(SEXP handle,
1150
  SEXP num_iteration,
1151
  SEXP feature_importance_type) {
1152
1153
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
1154
  _AssertBoosterHandleNotNull(handle);
1155
  SEXP model_str;
1156
  int64_t out_len = 0;
1157
  int64_t buf_len = 1024 * 1024;
1158
1159
  int num_iter = Rf_asInteger(num_iteration);
  int importance_type = Rf_asInteger(feature_importance_type);
1160
  std::vector<char> inner_char_buf(buf_len);
1161
  CHECK_CALL(LGBM_BoosterDumpModel(R_ExternalPtrAddr(handle), 0, num_iter, importance_type, buf_len, &out_len, inner_char_buf.data()));
1162
1163
1164
  // if the model string was larger than the initial buffer, allocate a bigger buffer and try again
  if (out_len > buf_len) {
    inner_char_buf.resize(out_len);
1165
    CHECK_CALL(LGBM_BoosterDumpModel(R_ExternalPtrAddr(handle), 0, num_iter, importance_type, out_len, &out_len, inner_char_buf.data()));
1166
  }
1167
1168
1169
  model_str = PROTECT(safe_R_string(static_cast<R_xlen_t>(1), &cont_token));
  SET_STRING_ELT(model_str, 0, safe_R_mkChar(inner_char_buf.data(), &cont_token));
  UNPROTECT(2);
1170
  return model_str;
1171
  R_API_END();
Guolin Ke's avatar
Guolin Ke committed
1172
}
1173

1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
SEXP LGBM_DumpParamAliases_R() {
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
  SEXP aliases_str;
  int64_t out_len = 0;
  int64_t buf_len = 1024 * 1024;
  std::vector<char> inner_char_buf(buf_len);
  CHECK_CALL(LGBM_DumpParamAliases(buf_len, &out_len, inner_char_buf.data()));
  // if aliases string was larger than the initial buffer, allocate a bigger buffer and try again
  if (out_len > buf_len) {
    inner_char_buf.resize(out_len);
    CHECK_CALL(LGBM_DumpParamAliases(out_len, &out_len, inner_char_buf.data()));
  }
  aliases_str = PROTECT(safe_R_string(static_cast<R_xlen_t>(1), &cont_token));
  SET_STRING_ELT(aliases_str, 0, safe_R_mkChar(inner_char_buf.data(), &cont_token));
  UNPROTECT(2);
  return aliases_str;
  R_API_END();
}

1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
SEXP LGBM_BoosterGetLoadedParam_R(SEXP handle) {
  SEXP cont_token = PROTECT(R_MakeUnwindCont());
  R_API_BEGIN();
  _AssertBoosterHandleNotNull(handle);
  SEXP params_str;
  int64_t out_len = 0;
  int64_t buf_len = 1024 * 1024;
  std::vector<char> inner_char_buf(buf_len);
  CHECK_CALL(LGBM_BoosterGetLoadedParam(R_ExternalPtrAddr(handle), buf_len, &out_len, inner_char_buf.data()));
  // if aliases string was larger than the initial buffer, allocate a bigger buffer and try again
  if (out_len > buf_len) {
    inner_char_buf.resize(out_len);
    CHECK_CALL(LGBM_BoosterGetLoadedParam(R_ExternalPtrAddr(handle), out_len, &out_len, inner_char_buf.data()));
  }
  params_str = PROTECT(safe_R_string(static_cast<R_xlen_t>(1), &cont_token));
  SET_STRING_ELT(params_str, 0, safe_R_mkChar(inner_char_buf.data(), &cont_token));
  UNPROTECT(2);
  return params_str;
  R_API_END();
}

1215
1216
// .Call() calls
static const R_CallMethodDef CallEntries[] = {
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
  {"LGBM_HandleIsNull_R"                         , (DL_FUNC) &LGBM_HandleIsNull_R                         , 1},
  {"LGBM_DatasetCreateFromFile_R"                , (DL_FUNC) &LGBM_DatasetCreateFromFile_R                , 3},
  {"LGBM_DatasetCreateFromCSC_R"                 , (DL_FUNC) &LGBM_DatasetCreateFromCSC_R                 , 8},
  {"LGBM_DatasetCreateFromMat_R"                 , (DL_FUNC) &LGBM_DatasetCreateFromMat_R                 , 5},
  {"LGBM_DatasetGetSubset_R"                     , (DL_FUNC) &LGBM_DatasetGetSubset_R                     , 4},
  {"LGBM_DatasetSetFeatureNames_R"               , (DL_FUNC) &LGBM_DatasetSetFeatureNames_R               , 2},
  {"LGBM_DatasetGetFeatureNames_R"               , (DL_FUNC) &LGBM_DatasetGetFeatureNames_R               , 1},
  {"LGBM_DatasetSaveBinary_R"                    , (DL_FUNC) &LGBM_DatasetSaveBinary_R                    , 2},
  {"LGBM_DatasetFree_R"                          , (DL_FUNC) &LGBM_DatasetFree_R                          , 1},
  {"LGBM_DatasetSetField_R"                      , (DL_FUNC) &LGBM_DatasetSetField_R                      , 4},
  {"LGBM_DatasetGetFieldSize_R"                  , (DL_FUNC) &LGBM_DatasetGetFieldSize_R                  , 3},
  {"LGBM_DatasetGetField_R"                      , (DL_FUNC) &LGBM_DatasetGetField_R                      , 3},
  {"LGBM_DatasetUpdateParamChecking_R"           , (DL_FUNC) &LGBM_DatasetUpdateParamChecking_R           , 2},
  {"LGBM_DatasetGetNumData_R"                    , (DL_FUNC) &LGBM_DatasetGetNumData_R                    , 2},
  {"LGBM_DatasetGetNumFeature_R"                 , (DL_FUNC) &LGBM_DatasetGetNumFeature_R                 , 2},
  {"LGBM_DatasetGetFeatureNumBin_R"              , (DL_FUNC) &LGBM_DatasetGetFeatureNumBin_R              , 3},
  {"LGBM_BoosterCreate_R"                        , (DL_FUNC) &LGBM_BoosterCreate_R                        , 2},
  {"LGBM_BoosterFree_R"                          , (DL_FUNC) &LGBM_BoosterFree_R                          , 1},
  {"LGBM_BoosterCreateFromModelfile_R"           , (DL_FUNC) &LGBM_BoosterCreateFromModelfile_R           , 1},
  {"LGBM_BoosterLoadModelFromString_R"           , (DL_FUNC) &LGBM_BoosterLoadModelFromString_R           , 1},
  {"LGBM_BoosterMerge_R"                         , (DL_FUNC) &LGBM_BoosterMerge_R                         , 2},
  {"LGBM_BoosterAddValidData_R"                  , (DL_FUNC) &LGBM_BoosterAddValidData_R                  , 2},
  {"LGBM_BoosterResetTrainingData_R"             , (DL_FUNC) &LGBM_BoosterResetTrainingData_R             , 2},
  {"LGBM_BoosterResetParameter_R"                , (DL_FUNC) &LGBM_BoosterResetParameter_R                , 2},
  {"LGBM_BoosterGetNumClasses_R"                 , (DL_FUNC) &LGBM_BoosterGetNumClasses_R                 , 2},
  {"LGBM_BoosterGetNumFeature_R"                 , (DL_FUNC) &LGBM_BoosterGetNumFeature_R                 , 1},
1243
  {"LGBM_BoosterGetLoadedParam_R"                , (DL_FUNC) &LGBM_BoosterGetLoadedParam_R                , 1},
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
  {"LGBM_BoosterUpdateOneIter_R"                 , (DL_FUNC) &LGBM_BoosterUpdateOneIter_R                 , 1},
  {"LGBM_BoosterUpdateOneIterCustom_R"           , (DL_FUNC) &LGBM_BoosterUpdateOneIterCustom_R           , 4},
  {"LGBM_BoosterRollbackOneIter_R"               , (DL_FUNC) &LGBM_BoosterRollbackOneIter_R               , 1},
  {"LGBM_BoosterGetCurrentIteration_R"           , (DL_FUNC) &LGBM_BoosterGetCurrentIteration_R           , 2},
  {"LGBM_BoosterGetUpperBoundValue_R"            , (DL_FUNC) &LGBM_BoosterGetUpperBoundValue_R            , 2},
  {"LGBM_BoosterGetLowerBoundValue_R"            , (DL_FUNC) &LGBM_BoosterGetLowerBoundValue_R            , 2},
  {"LGBM_BoosterGetEvalNames_R"                  , (DL_FUNC) &LGBM_BoosterGetEvalNames_R                  , 1},
  {"LGBM_BoosterGetEval_R"                       , (DL_FUNC) &LGBM_BoosterGetEval_R                       , 3},
  {"LGBM_BoosterGetNumPredict_R"                 , (DL_FUNC) &LGBM_BoosterGetNumPredict_R                 , 3},
  {"LGBM_BoosterGetPredict_R"                    , (DL_FUNC) &LGBM_BoosterGetPredict_R                    , 3},
  {"LGBM_BoosterPredictForFile_R"                , (DL_FUNC) &LGBM_BoosterPredictForFile_R                , 10},
  {"LGBM_BoosterCalcNumPredict_R"                , (DL_FUNC) &LGBM_BoosterCalcNumPredict_R                , 8},
  {"LGBM_BoosterPredictForCSC_R"                 , (DL_FUNC) &LGBM_BoosterPredictForCSC_R                 , 14},
  {"LGBM_BoosterPredictForCSR_R"                 , (DL_FUNC) &LGBM_BoosterPredictForCSR_R                 , 12},
  {"LGBM_BoosterPredictForCSRSingleRow_R"        , (DL_FUNC) &LGBM_BoosterPredictForCSRSingleRow_R        , 11},
  {"LGBM_BoosterPredictForCSRSingleRowFastInit_R", (DL_FUNC) &LGBM_BoosterPredictForCSRSingleRowFastInit_R, 8},
  {"LGBM_BoosterPredictForCSRSingleRowFast_R"    , (DL_FUNC) &LGBM_BoosterPredictForCSRSingleRowFast_R    , 4},
  {"LGBM_BoosterPredictSparseOutput_R"           , (DL_FUNC) &LGBM_BoosterPredictSparseOutput_R           , 10},
  {"LGBM_BoosterPredictForMat_R"                 , (DL_FUNC) &LGBM_BoosterPredictForMat_R                 , 11},
  {"LGBM_BoosterPredictForMatSingleRow_R"        , (DL_FUNC) &LGBM_BoosterPredictForMatSingleRow_R        , 9},
  {"LGBM_BoosterPredictForMatSingleRowFastInit_R", (DL_FUNC) &LGBM_BoosterPredictForMatSingleRowFastInit_R, 8},
  {"LGBM_BoosterPredictForMatSingleRowFast_R"    , (DL_FUNC) &LGBM_BoosterPredictForMatSingleRowFast_R    , 3},
  {"LGBM_BoosterSaveModel_R"                     , (DL_FUNC) &LGBM_BoosterSaveModel_R                     , 4},
  {"LGBM_BoosterSaveModelToString_R"             , (DL_FUNC) &LGBM_BoosterSaveModelToString_R             , 3},
  {"LGBM_BoosterDumpModel_R"                     , (DL_FUNC) &LGBM_BoosterDumpModel_R                     , 3},
  {"LGBM_NullBoosterHandleError_R"               , (DL_FUNC) &LGBM_NullBoosterHandleError_R               , 0},
  {"LGBM_DumpParamAliases_R"                     , (DL_FUNC) &LGBM_DumpParamAliases_R                     , 0},
1271
1272
1273
  {NULL, NULL, 0}
};

1274
1275
LIGHTGBM_C_EXPORT void R_init_lightgbm(DllInfo *dll);

1276
1277
1278
1279
void R_init_lightgbm(DllInfo *dll) {
  R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
  R_useDynamicSymbols(dll, FALSE);
}