Implementation:Dotnet Machinelearning MatrixFactorizationNative
| Knowledge Sources | |
|---|---|
| Domains | Machine Learning, Native Interop, Recommendation Systems |
| Last Updated | 2026-02-09 12:00 GMT |
Overview
C-style bridge layer that wraps the LIBMF matrix factorization library, translating between ML.NET's managed memory representations and LIBMF's native data structures to enable recommendation system training and prediction from .NET.
Description
UnmanagedMemory.cpp provides the native interop surface for ML.NET's matrix factorization trainer. The file defines:
- Bridge structs (mf_parameter_bridge, mf_problem_bridge, mf_model_bridge) that mirror LIBMF's internal structs but use flat, blittable layouts suitable for P/Invoke marshalling. These bridge structs avoid pointers-to-pointers and other patterns that complicate cross-language memory management.
- Translation functions (TranslateToParam, TranslateToProblem, TranslateToModel, TranslateToModelBridge) that convert between bridge structs and LIBMF's native structs. This includes deep-copying sparse matrix data and allocating/deallocating native memory for model factor matrices.
- Exported API functions that provide the complete matrix factorization workflow: training (MFTrain), training with held-out validation (MFTrainWithValidation), cross-validation (MFCrossValidation), prediction (MFPredict), and resource cleanup (MFDestroyModel).
The bridge pattern isolates LIBMF's internal memory management from the .NET garbage collector, preventing use-after-free and double-free issues that commonly arise in native interop scenarios.
Usage
Use this native library when building recommendation systems with ML.NET's MatrixFactorizationTrainer. The managed trainer marshals the sparse user-item interaction matrix into the bridge format, calls MFTrain or MFTrainWithValidation, and receives back a trained model that can predict ratings for unseen user-item pairs via MFPredict. Common scenarios include:
- Collaborative filtering for product recommendations
- Rating prediction for content personalization
- Missing value imputation in sparse matrices
Code Reference
Source Location
- Repository: Dotnet_Machinelearning
- File: src/Native/MatrixFactorizationNative/UnmanagedMemory.cpp
- Lines: 1-126
Signature
// Bridge structures for P/Invoke marshalling
struct mf_parameter_bridge {
int fun; // Loss function type
int k; // Number of latent factors
int nr_threads; // Thread count for parallel training
int nr_bins; // Number of bins for data partitioning
int nr_iters; // Number of SGD iterations
float lambda_p1; // L1 regularization for P matrix
float lambda_p2; // L2 regularization for P matrix
float lambda_q1; // L1 regularization for Q matrix
float lambda_q2; // L2 regularization for Q matrix
float eta; // Learning rate
bool do_nmf; // Non-negative MF flag
bool quiet; // Suppress output flag
bool copy_data; // Copy input data flag
};
struct mf_problem_bridge {
int m; // Number of rows (users)
int n; // Number of columns (items)
long nnz; // Number of non-zero entries
float* R_buf; // Flat buffer: [row_idx, col_idx, value, ...]
};
struct mf_model_bridge {
int fun; // Loss function type
int m; // Number of rows
int n; // Number of columns
int k; // Number of latent factors
float b; // Global bias term
float* P_buf; // User factor matrix (m x k)
float* Q_buf; // Item factor matrix (n x k)
};
// Exported API functions
EXPORT_API(void) MFDestroyModel(mf_model_bridge* model_bridge);
EXPORT_API(mf_model_bridge*) MFTrain(
mf_problem_bridge* prob_bridge,
mf_parameter_bridge* param_bridge
);
EXPORT_API(mf_model_bridge*) MFTrainWithValidation(
mf_problem_bridge* tr_bridge,
mf_problem_bridge* va_bridge,
mf_parameter_bridge* param_bridge
);
EXPORT_API(float) MFCrossValidation(
mf_problem_bridge* prob_bridge,
int nr_folds,
mf_parameter_bridge* param_bridge
);
EXPORT_API(float) MFPredict(
mf_model_bridge* model_bridge,
int p_idx,
int q_idx
);
Import
// P/Invoke declarations (managed side)
[DllImport("MatrixFactorizationNative")]
internal static extern IntPtr MFTrain(
ref MfProblemBridge prob, ref MfParameterBridge param);
[DllImport("MatrixFactorizationNative")]
internal static extern IntPtr MFTrainWithValidation(
ref MfProblemBridge trainProb, ref MfProblemBridge valProb,
ref MfParameterBridge param);
[DllImport("MatrixFactorizationNative")]
internal static extern float MFCrossValidation(
ref MfProblemBridge prob, int nrFolds,
ref MfParameterBridge param);
[DllImport("MatrixFactorizationNative")]
internal static extern float MFPredict(
IntPtr model, int pIdx, int qIdx);
[DllImport("MatrixFactorizationNative")]
internal static extern void MFDestroyModel(IntPtr model);
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| prob_bridge | mf_problem_bridge* | Yes | Sparse matrix in bridge format containing user-item-rating triples |
| param_bridge | mf_parameter_bridge* | Yes | Training hyperparameters (latent factors, learning rate, regularization, iterations) |
| tr_bridge | mf_problem_bridge* | Yes (validation) | Training set sparse matrix |
| va_bridge | mf_problem_bridge* | Yes (validation) | Validation set sparse matrix for early stopping |
| nr_folds | int | Yes (CV) | Number of cross-validation folds |
| model_bridge | mf_model_bridge* | Yes (predict/destroy) | Pointer to a trained model |
| p_idx | int | Yes (predict) | Row index (user ID) for prediction |
| q_idx | int | Yes (predict) | Column index (item ID) for prediction |
Outputs
| Name | Type | Description |
|---|---|---|
| return (MFTrain) | mf_model_bridge* | Pointer to trained model containing P and Q factor matrices |
| return (MFTrainWithValidation) | mf_model_bridge* | Pointer to trained model; training stops early if validation error increases |
| return (MFCrossValidation) | float | Average cross-validation error across all folds |
| return (MFPredict) | float | Predicted rating for the given user-item pair (dot product of latent factors plus bias) |
Bridge Translation Functions
| Function | Direction | Description |
|---|---|---|
| TranslateToParam | Bridge to LIBMF | Converts mf_parameter_bridge to LIBMF's mf_parameter struct |
| TranslateToProblem | Bridge to LIBMF | Converts flat R_buf array into LIBMF's mf_problem with mf_node array; each triple (row, col, val) becomes one node |
| TranslateToModelBridge | LIBMF to Bridge | Deep-copies trained mf_model factor matrices into flat P_buf and Q_buf arrays for marshalling |
| TranslateToModel | Bridge to LIBMF | Reconstructs an mf_model from bridge format (used when loading a saved model for prediction) |
Usage Examples
// Training a matrix factorization model for recommendations
var pipeline = mlContext.Transforms.Conversion
.MapValueToKey("userIdEncoded", "UserId")
.Append(mlContext.Transforms.Conversion
.MapValueToKey("movieIdEncoded", "MovieId"))
.Append(mlContext.Recommendation().Trainers.MatrixFactorization(
labelColumnName: "Rating",
matrixColumnIndexColumnName: "userIdEncoded",
matrixRowIndexColumnName: "movieIdEncoded",
numberOfIterations: 20,
approximationRank: 64, // k latent factors
learningRate: 0.01));
// Internally calls MFTrain via P/Invoke
var model = pipeline.Fit(trainingData);
// Prediction internally calls MFPredict
var prediction = model.Transform(testData);
// Cross-validation to evaluate model quality
// Internally calls MFCrossValidation with nr_folds
var cvResults = mlContext.Recommendation()
.CrossValidate(data, pipeline, numberOfFolds: 5);