double LVlinear_predict(lvError *lvErr, const struct LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in){ try{ // Convert LVsvm_model to svm_model std::unique_ptr<model> model(new model); LVConvertModel(model_in, model.get()); double label = predict(model.get(), reinterpret_cast<feature_node*>((*x_in)->elt)); return label; } catch (LVException &ex) { ex.returnError(lvErr); return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); return std::nan(""); } }
void LVlinear_train(lvError *lvErr, const LVlinear_problem *prob_in, const LVlinear_parameter *param_in, LVlinear_model * model_out){ try{ // Input verification: Problem dimensions if ((*(prob_in->x))->dimSize != (*(prob_in->y))->dimSize) throw LVException(__FILE__, __LINE__, "The problem must have an equal number of labels and feature vectors (x and y)."); //-- Convert problem std::unique_ptr<problem> prob(new problem); uint32_t nr_nodes = (*(prob_in->y))->dimSize; prob->l = nr_nodes; prob->y = (*(prob_in->y))->elt; // Create and array of pointers (sparse datastructure) std::unique_ptr<feature_node*[]> x(new feature_node*[nr_nodes]); prob->x = x.get(); auto x_in = prob_in->x; for (unsigned int i = 0; i < (*x_in)->dimSize; i++){ // Assign the innermost svm_node array pointers to the array of pointers auto xi_in_Hdl = (*x_in)->elt[i]; x[i] = reinterpret_cast<feature_node*>((*xi_in_Hdl)->elt); } //-- Convert parameters std::unique_ptr<parameter> param(new parameter()); LVConvertParameter(param_in, param.get()); // Verify parameters const char * param_check = check_parameter(prob.get(), param.get()); if (param_check != nullptr) throw LVException(__FILE__, __LINE__, "Parameter check failed with the following error: " + std::string(param_check)); // Train model model *result = train(prob.get(), param.get()); // Copy model to LabVIEW memory LVConvertModel(result, model_out); // Release memory allocated by train free_model_content(result); } catch (LVException &ex) { ex.returnError(lvErr); // To avoid LabVIEW reading and utilizing bad memory, the dimension sizes of arrays is set to zero (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; } }
double LVlinear_predict_values(lvError *lvErr, const LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in, LVArray_Hdl<double> dec_values_out){ try{ // Input validation: Uninitialized model if (model_in == nullptr || model_in->w == nullptr || (*model_in->w)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Uninitialized model passed to liblinear_predict_values."); // Input validation: Empty feature vector if (x_in == nullptr || (*x_in)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Empty feature vector passed to liblinear_predict_values."); // Input validation: Final index -1? if ((*x_in)->elt[(*x_in)->dimSize - 1].index != -1) throw LVException(__FILE__, __LINE__, "The index of the last element of the feature vector needs to be -1 (liblinear_predict_values)."); // Convert LVsvm_model to svm_model auto mdl = std::make_unique<model>(); LVConvertModel(*model_in, *mdl); int nr_class = model_in->nr_class; int solver = (model_in->param).solver_type; // Set up output array int nr_dec = 0; if (nr_class <= 2){ if (solver == MCSVM_CS) nr_dec = 2; else nr_dec = 1; } else { nr_dec = nr_class; } LVResizeNumericArrayHandle(dec_values_out, nr_dec); (*dec_values_out)->dimSize = nr_dec; double predicted_label = predict_values(mdl.get(), reinterpret_cast<feature_node*>((*x_in)->elt), (*dec_values_out)->elt); return predicted_label; } catch (LVException &ex) { ex.returnError(lvErr); (*dec_values_out)->dimSize = 0; return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); (*dec_values_out)->dimSize = 0; return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); (*dec_values_out)->dimSize = 0; return std::nan(""); } }
void LVlinear_save_model(lvError *lvErr, const char *path_in, const LVlinear_model *model_in){ try{ errno = 0; // Convert LVsvm_model to svm_model auto mdl = std::make_unique<model>(); LVConvertModel(*model_in, *mdl); int err = save_model(path_in, mdl.get()); if (err == -1){ // Allocate room for output error message (truncated if buffer is too small) const size_t bufSz = 256; char buf[bufSz] = ""; std::string errstr; #if defined(_WIN32) || defined(_WIN64) if (strerror_s(buf, bufSz, errno) != 0) errstr = buf; else errstr = "Unknown error"; #elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE if (strerror_r(errno, buf, bufSz) != 0) errstr = buf; else errstr = "Unknown error"; #else char* gnuerr = strerror_r(errno, buf, bufSz); if (gnuerr != nullptr) errstr = gnuerr; else errstr = "Unknown error"; #endif errno = 0; throw LVException(__FILE__, __LINE__, "Model load operation failed (" + errstr + ")."); } } catch (LVException &ex) { ex.returnError(lvErr); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); } }
double LVlinear_predict_probability(lvError *lvErr, const LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in, LVArray_Hdl<double> prob_estimates_out){ try{ // Input validation: Uninitialized model if (model_in == nullptr || model_in->w == nullptr || (*model_in->w)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Uninitialized model passed to liblinear_predict_probability."); // Input validation: Empty feature vector if (x_in == nullptr || (*x_in)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Empty feature vector passed to liblinear_predict_probability."); // Input validation: Final index -1? if ((*x_in)->elt[(*x_in)->dimSize - 1].index != -1) throw LVException(__FILE__, __LINE__, "The index of the last element of the feature vector needs to be -1 (liblinear_predict_probability)."); // Convert LVsvm_model to svm_model auto mdl = std::make_unique<model>(); LVConvertModel(*model_in, *mdl); // Check probability model int valid_probability = check_probability_model(mdl.get()); if (!valid_probability) throw LVException(__FILE__, __LINE__, "The selected solver type does not support probability output."); // Allocate room for probability estimates LVResizeNumericArrayHandle(prob_estimates_out, mdl->nr_class); (*prob_estimates_out)->dimSize = mdl->nr_class; double highest_prob_label = predict_probability(mdl.get(), reinterpret_cast<feature_node*>((*x_in)->elt), (*prob_estimates_out)->elt); return highest_prob_label; } catch (LVException &ex) { ex.returnError(lvErr); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } }
double LVlinear_predict_values(lvError *lvErr, const LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in, LVArray_Hdl<double> dec_values_out){ try{ // Convert LVsvm_model to svm_model std::unique_ptr<model> model(new model); LVConvertModel(model_in, model.get()); int nr_class = model_in->nr_class; int solver = (model_in->param).solver_type; // Set up output array int nr_dec = 0; if (nr_class <= 2){ if (solver == MCSVM_CS) nr_dec = 2; else nr_dec = 1; } else { nr_dec = nr_class; } LVResizeNumericArrayHandle(dec_values_out, nr_dec); (*dec_values_out)->dimSize = nr_dec; double predicted_label = predict_values(model.get(), reinterpret_cast<feature_node*>((*x_in)->elt), (*dec_values_out)->elt); return predicted_label; } catch (LVException &ex) { ex.returnError(lvErr); (*dec_values_out)->dimSize = 0; return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); (*dec_values_out)->dimSize = 0; return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); (*dec_values_out)->dimSize = 0; return std::nan(""); } }
double LVlinear_predict_probability(lvError *lvErr, const LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in, LVArray_Hdl<double> prob_estimates_out){ try{ // Convert LVsvm_model to svm_model std::unique_ptr<model> model(new model); LVConvertModel(model_in, model.get()); // Check probability model int valid_probability = check_probability_model(model.get()); if (!valid_probability) throw LVException(__FILE__, __LINE__, "The model does not support probability output."); // Allocate room for probability estimates LVResizeNumericArrayHandle(prob_estimates_out, model->nr_class); (*prob_estimates_out)->dimSize = model->nr_class; double highest_prob_label = predict_probability(model.get(), reinterpret_cast<feature_node*>((*x_in)->elt), (*prob_estimates_out)->elt); return highest_prob_label; } catch (LVException &ex) { ex.returnError(lvErr); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); (*prob_estimates_out)->dimSize = 0; return std::nan(""); } }
double LVlinear_predict(lvError *lvErr, const struct LVlinear_model *model_in, const LVArray_Hdl<LVlinear_node> x_in){ try{ // Input validation: Uninitialized model if (model_in == nullptr || model_in->w == nullptr || (*model_in->w)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Uninitialized model passed to liblinear_predict."); // Input validation: Empty feature vector if (x_in == nullptr || (*x_in)->dimSize == 0) throw LVException(__FILE__, __LINE__, "Empty feature vector passed to liblinear_predict."); // Input validation: Final index -1? if ((*x_in)->elt[(*x_in)->dimSize - 1].index != -1) throw LVException(__FILE__, __LINE__, "The index of the last element of the feature vector needs to be -1 (liblinear_predict)."); // Convert LVsvm_model to svm_model auto mdl = std::make_unique<model>(); LVConvertModel(*model_in, *mdl); double label = predict(mdl.get(), reinterpret_cast<feature_node*>((*x_in)->elt)); return label; } catch (LVException &ex) { ex.returnError(lvErr); return std::nan(""); } catch (std::exception &ex) { LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); return std::nan(""); } catch (...) { LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); return std::nan(""); } }
void LVlinear_load_model(lvError *lvErr, const char *path_in, LVlinear_model *model_out){ try{ errno = 0; model *mdl = load_model(path_in); if (mdl == nullptr){ // Allocate room for output error message (truncated if buffer is too small) const size_t bufSz = 256; char buf[bufSz] = ""; std::string errstr; #if defined(_WIN32) || defined(_WIN64) if (strerror_s(buf, bufSz, errno) != 0) errstr = buf; else errstr = "Unknown error"; #elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE if (strerror_r(errno, buf, bufSz) != 0) errstr = buf; else errstr = "Unknown error"; #else char* gnuerr = strerror_r(errno, buf, bufSz); if (gnuerr != nullptr) errstr = gnuerr; else errstr = "Unknown error"; #endif errno = 0; throw LVException(__FILE__, __LINE__, "Model load operation failed (" + errstr + ")."); } else{ // liblinear returns uninitialized values for the parameters (except solver type) (mdl->param).C = 0; (mdl->param).eps = 0; (mdl->param).init_sol = nullptr; (mdl->param).nr_weight = 0; (mdl->param).p = 0; (mdl->param).weight = nullptr; (mdl->param).weight_label = nullptr; LVConvertModel(*mdl, *model_out); free_model_content(mdl); } } catch (LVException &ex) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; ex.returnError(lvErr); } catch (std::exception &ex) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); } catch (...) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); } }
void LVlinear_train(lvError *lvErr, const LVlinear_problem *prob_in, const LVlinear_parameter *param_in, LVlinear_model * model_out){ try{ // Input verification: Nonempty problem if (prob_in->x == nullptr || (*(prob_in->x))->dimSize == 0) throw LVException(__FILE__, __LINE__, "Empty problem passed to liblinear_train."); // Input verification: Problem dimensions if ((*(prob_in->x))->dimSize != (*(prob_in->y))->dimSize) throw LVException(__FILE__, __LINE__, "The problem must have an equal number of labels and feature vectors (x and y)."); uint32_t nr_nodes = (*(prob_in->y))->dimSize; // Input validation: Number of feature vectors too large (exceeds max signed int) if(nr_nodes > INT_MAX) throw LVException(__FILE__, __LINE__, "Number of feature vectors too large (grater than " + std::to_string(INT_MAX) + ")"); //-- Convert problem auto prob = std::make_unique<problem>(); prob->l = nr_nodes; prob->y = (*(prob_in->y))->elt; prob->n = 0; // Calculated later prob->bias = prob_in->bias; // Create and array of pointers (sparse datastructure) auto x = std::make_unique<feature_node*[]>(nr_nodes); prob->x = x.get(); auto x_in = prob_in->x; for (unsigned int i = 0; i < (*x_in)->dimSize; i++){ // Assign the innermost svm_node array pointers to the array of pointers auto xi_in_Hdl = (*x_in)->elt[i]; x[i] = reinterpret_cast<feature_node*>((*xi_in_Hdl)->elt); // Input validation: Final index -1? if ((*xi_in_Hdl)->elt[(*xi_in_Hdl)->dimSize - 1].index != -1) throw LVException(__FILE__, __LINE__, "The index of the last element of each feature vector needs to be -1 (liblinear_train)."); // Calculate the max index // This detail is not exposed in LabVIEW, as setting the wrong value causes a crash // Second to last element should contain the max index for that feature vector (as they are in ascending order). auto secondToLast = (*xi_in_Hdl)->dimSize - 2; // Ignoring -1 index auto largestIndex = (*xi_in_Hdl)->elt[secondToLast].index; if (secondToLast >= 0 && largestIndex > prob->n) prob->n = largestIndex; } //-- Convert parameters auto param = std::make_unique<parameter>(); LVConvertParameter(*param_in, *param); // Verify parameters const char * param_check = check_parameter(prob.get(), param.get()); if (param_check != nullptr) throw LVException(__FILE__, __LINE__, "Parameter check failed with the following error: " + std::string(param_check)); // Train model model *result = train(prob.get(), param.get()); // Copy model to LabVIEW memory LVConvertModel(*result, *model_out); // Release memory allocated by train free_model_content(result); } catch (LVException &ex) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; ex.returnError(lvErr); } catch (std::exception &ex) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; LVException::returnStdException(lvErr, __FILE__, __LINE__, ex); } catch (...) { (*(model_out->label))->dimSize = 0; (*(model_out->w))->dimSize = 0; (*(model_out->param).weight)->dimSize = 0; (*(model_out->param).weight_label)->dimSize = 0; LVException ex(__FILE__, __LINE__, "Unknown exception has occurred"); ex.returnError(lvErr); } }