Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Dotnet Machinelearning FastTree SurplusMART Derivatives

From Leeroopedia


Knowledge Sources
Domains Machine Learning, Learning to Rank, Information Retrieval
Last Updated 2026-02-09 12:00 GMT

Overview

WinLossSurplus-specific gradient computation for LambdaMART, implementing a margin-based pairwise ranking objective that emphasizes the surplus between document score differences and relevance gaps.

Description

The getsurplusderivatives.cpp module (157 lines) implements a variant of the LambdaMART gradient computation known as SurplusMART (or WinLossSurplus). While standard LambdaMART computes lambda gradients based on the change in NDCG from swapping two documents, SurplusMART modifies the gradient computation to incorporate a surplus term: the margin by which the model's score difference between a document pair exceeds or falls short of the desired relevance gap.

The key differences from the standard C_GetDerivatives function are:

  • Margin-based lambda computation: Rather than computing lambdas purely from the NDCG swap delta, SurplusMART factors in the difference between the current score gap and an ideal score gap derived from the relevance labels. This encourages the model not just to rank documents correctly but to produce score separations proportional to relevance differences.
  • Simplified parameter set: SurplusMART does not support secondary metrics, risk-aware ranking, or the extended parametrization of the standard derivative function. This results in a more streamlined implementation focused on the surplus objective.
  • Win/loss accounting: The surplus term creates an asymmetry between winning pairs (where the higher-relevance document already has a higher score) and losing pairs (where the ranking is incorrect). The gradient magnitude differs between these cases, pushing the model harder to correct ranking inversions while still refining already-correct orderings.

The function iterates over all document pairs within a query where the relevance labels differ. For each pair, it computes the sigmoid of the score difference (via table lookup), the discount factors at both positions, the gain difference between the two relevance levels, and the surplus-adjusted lambda gradient. The resulting per-document lambdas and weights are accumulated and returned for use as tree-building targets.

Usage

SurplusMART is used as an alternative ranking objective in scenarios where score calibration matters in addition to ranking order. It is selected through the managed ML.NET trainer configuration when the WinLossSurplus cost function is specified. The managed layer calls this function in the same context as C_GetDerivatives -- once per query per boosting iteration -- but routes to this implementation when the surplus objective is active.

Code Reference

Source Location

Signature

extern "C" {

EXPORT_API(void) C_GetSurplusDerivatives(
    int numDocuments,
    int begin,
    int *pPermutation,
    short *pLabels,
    double *pScores,
    double *pLambdas,
    double *pWeights,
    double *pDiscount,
    double *pGainLabels,
    double *sigmoidTable,
    double minScore,
    double maxScore,
    int sigmoidTableLength,
    double scoreToSigmoidTableFactor,
    char costFunctionParam,
    double distanceWeight2,
    double *pLambdaSum,
    double minDoubleValue
);

}

Import

// P/Invoke declaration from managed ML.NET LambdaMART trainer
[DllImport("FastTreeNative")]
private static extern unsafe void C_GetSurplusDerivatives(
    int numDocuments,
    int begin,
    int* pPermutation,
    short* pLabels,
    double* pScores,
    double* pLambdas,
    double* pWeights,
    double* pDiscount,
    double* pGainLabels,
    double* sigmoidTable,
    double minScore,
    double maxScore,
    int sigmoidTableLength,
    double scoreToSigmoidTableFactor,
    byte costFunctionParam,
    double distanceWeight2,
    double* pLambdaSum,
    double minDoubleValue);

I/O Contract

Inputs

Name Type Required Description
numDocuments int Yes Number of documents in this query group.
begin int Yes Starting index of this query's documents within the global arrays.
pPermutation int* Yes Permutation array mapping local document positions to global indices, ordered by current model score (descending).
pLabels short* Yes Relevance labels for each document (e.g., 0-4 scale).
pScores double* Yes Current model scores for each document.
pLambdas double* Yes (in/out) Output array for surplus-adjusted lambda gradients.
pWeights double* Yes (in/out) Output array for Newton step weights.
pDiscount double* Yes Position discount factors, typically 1/log2(rank+1) for NDCG-based discounting.
pGainLabels double* Yes Precomputed gain values per relevance label (e.g., 2^label - 1).
sigmoidTable double* Yes Pre-computed sigmoid lookup table for fast pairwise probability computation.
minScore double Yes Minimum score difference in the sigmoid table range.
maxScore double Yes Maximum score difference in the sigmoid table range.
sigmoidTableLength int Yes Length of the sigmoid lookup table.
scoreToSigmoidTableFactor double Yes Scaling factor to convert score differences to sigmoid table indices.
costFunctionParam char Yes Cost function selector controlling the surplus variant.
distanceWeight2 double Yes Exponent for position-distance weighting between document pairs.
pLambdaSum double* Yes (out) Output: sum of all lambda values for this query.
minDoubleValue double Yes Minimum double value to prevent underflow in lambda computation.

Outputs

Name Type Description
pLambdas double* Per-document surplus-adjusted lambda gradients. Reflects both ranking correctness and score margin surplus.
pWeights double* Per-document Newton step weights for weighted least squares leaf value computation.
pLambdaSum double* Scalar sum of absolute lambda values for the query, used for convergence monitoring.

Usage Examples

// Compute SurplusMART gradients for a query with 30 documents
int numDocs = 30;
int begin = 0;
int permutation[30];     // sorted by descending score
short labels[30];        // relevance labels
double scores[30];       // current model scores
double lambdas[30] = {}; // zero-initialized output
double weights[30] = {}; // zero-initialized output
double discount[30];     // position discounts
double gainLabels[5] = {0.0, 1.0, 3.0, 7.0, 15.0};
double lambdaSum = 0.0;

// Pre-compute position discounts
for (int i = 0; i < numDocs; i++) {
    discount[i] = 1.0 / log2(i + 2.0);
}

// Sigmoid table setup
int sigmoidLen = 10000;
double sigmoidTable[10000];
double minS = -10.0, maxS = 10.0;
double factor = sigmoidLen / (maxS - minS);
for (int i = 0; i < sigmoidLen; i++) {
    double x = minS + i / factor;
    sigmoidTable[i] = 1.0 / (1.0 + exp(-x));
}

C_GetSurplusDerivatives(
    numDocs, begin, permutation, labels, scores,
    lambdas, weights, discount,
    gainLabels,
    sigmoidTable, minS, maxS, sigmoidLen, factor,
    'c',          // costFunctionParam
    0.0,          // distanceWeight2
    &lambdaSum,
    1e-300        // minDoubleValue
);

// lambdas[] now contains surplus-adjusted gradients.
// Compared to standard LambdaMART, these gradients also penalize
// insufficient score margins between differently-labeled documents.

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment