MCPcopy Create free account
hub / github.com/ciphermodelabs/ciphercore / compute_naive_auc

Function compute_naive_auc

ciphercore-base/src/ops/auc.rs:118–177  ·  view source on GitHub ↗
(y_true: Node, y_pred: Node, fp: &FixedPrecisionConfig)

Source from the content-addressed store, hash-verified

116}
117
118fn compute_naive_auc(y_true: Node, y_pred: Node, fp: &FixedPrecisionConfig) -> Result<Node> {
119 // This function doesn't account for equal predictions.
120 // Assuming all predictions are distinct:
121 // AUC = (number of pairs (i, j) such that y_pred[i] < y_pred[j] and y_true[i] < y_true[j]) / (number of pairs (i, j) such that y_true[i] < y_true[j]).
122 let g = y_true.get_graph();
123 let joined =
124 g.create_named_tuple(vec![("y_pred".into(), y_pred), ("y_true".into(), y_true)])?;
125 let joined = g.custom_op(
126 CustomOperation::new(SortByIntegerKey {
127 key: "y_pred".into(),
128 }),
129 vec![joined],
130 )?;
131 let y_true = joined.named_tuple_get("y_true".into())?;
132
133 // Compute AUC denominator, i.e. num_ones * num_zeros.
134 let num_ones = y_true.sum(vec![0])?.truncate(fp.denominator())?;
135 let n = y_true.get_type()?.get_dimensions()[0] as i64;
136 let n = constant_scalar(&g, n, INT64)?;
137 let num_zeros = n.subtract(num_ones.clone())?;
138 let denominator = num_ones.multiply(num_zeros)?;
139
140 // Compute AUC numerator.
141 let one = constant_scalar(&g, fp.denominator(), INT64)?;
142 let num_zeros_on_prefix = one.subtract(y_true.clone())?.cum_sum(0)?;
143 let num_zeros_before_one = num_zeros_on_prefix
144 .multiply(y_true)?
145 .truncate(fp.denominator())?;
146 let numerator = num_zeros_before_one
147 .sum(vec![0])?
148 .truncate(fp.denominator())?;
149
150 // Compute AUC.
151 let numerator = i64_to_i128(numerator)?;
152 let denominator = i64_to_i128(denominator)?;
153 let denom_bits = MAX_LOG_ARRAY_SIZE * 2;
154 // Note: GoldschmidtDivision requires denominator to be smaller than 2 ** denominator_cap_2k.
155 // We use 2 ** 40 as a hard-coded constant, meaning that sqrt(denominator) must be smaller than 2 ** 20 (imposing restriction on the number of elements in the array).
156 // We can potentially support larger arrays, if we first divide by num_ones, and then - by num_zeros.
157 let result = g.custom_op(
158 CustomOperation::new(GoldschmidtDivision {
159 // Use 7 = log_2(128) iterations.
160 iterations: 7,
161 denominator_cap_2k: denom_bits,
162 }),
163 vec![numerator, denominator],
164 )?;
165
166 let result = match denom_bits.cmp(&fp.fractional_bits) {
167 Ordering::Less => result.multiply(constant_scalar(
168 &g,
169 1 << (fp.fractional_bits - denom_bits),
170 INT128,
171 )?)?,
172 Ordering::Equal => result,
173 Ordering::Greater => result.truncate(1 << (denom_bits - fp.fractional_bits))?,
174 };
175

Callers 1

instantiateMethod · 0.85

Calls 15

constant_scalarFunction · 0.85
i64_to_i128Function · 0.85
i128_to_i64Function · 0.85
denominatorMethod · 0.80
get_dimensionsMethod · 0.80
cloneMethod · 0.80
cum_sumMethod · 0.80
get_graphMethod · 0.45
create_named_tupleMethod · 0.45
custom_opMethod · 0.45
named_tuple_getMethod · 0.45
truncateMethod · 0.45

Tested by

no test coverage detected