LCOV - code coverage report
Current view: top level - src - math_utils.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 22 22
Test Date: 2026-07-09 07:56:57 Functions: - 0 0

            Line data    Source code
       1              : // Copyright 2026 The Authors.
       2              : //
       3              : // Licensed under the Apache License, Version 2.0 (the "License");
       4              : // you may not use this file except in compliance with the License.
       5              : // You may obtain a copy of the License at
       6              : //
       7              : //     https://www.apache.org/licenses/LICENSE-2.0
       8              : //
       9              : // Unless required by applicable law or agreed to in writing, software
      10              : // distributed under the License is distributed on an "AS IS" BASIS,
      11              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : // See the License for the specific language governing permissions and
      13              : // limitations under the License.
      14              : 
      15              : import 'dart:math';
      16              : import 'dart:typed_data';
      17              : 
      18              : /// Produces a sentence-level embedding by averaging the token-level hidden
      19              : /// states produced by the ONNX model, weighted by [attentionMask].
      20              : ///
      21              : /// [hiddenState] is the flat list of float32 logits extracted from the
      22              : /// [OnnxTensor] returned by [OnnxSession.run] with shape `[seqLen * hiddenDim]`.
      23              : ///
      24              : /// [attentionMask] is the parallel list from [TokenizerOutput], length
      25              : /// `seqLen`. Padding positions (mask = 0) are excluded from the average.
      26              : ///
      27              : /// [seqLen] is the number of token positions.
      28              : ///
      29              : /// [hiddenDim] is the embedding dimension (e.g. 384 for BGE Small En v1.5,
      30              : /// 1024 for BGE-M3). Sourced from `spec.meta['dimensions'] as int` and
      31              : /// must be supplied by the caller — there is no default, as the dimension is
      32              : /// model-specific and must not be assumed.
      33              : ///
      34              : /// Returns a float32 list of [hiddenDim] elements. Returns a zero vector if
      35              : /// no attention-masked tokens are present (degenerate case).
      36            1 : Float32List meanPool(
      37              :   List<double> hiddenState,
      38              :   List<int> attentionMask, {
      39              :   int seqLen = 512,
      40              :   required int hiddenDim,
      41              : }) {
      42            1 :   final result = Float32List(hiddenDim);
      43              :   var active = 0;
      44            2 :   for (var t = 0; t < seqLen; t++) {
      45            2 :     if (attentionMask[t] != 1) continue;
      46            1 :     final offset = t * hiddenDim;
      47            2 :     for (var d = 0; d < hiddenDim; d++) {
      48            4 :       result[d] += hiddenState[offset + d];
      49              :     }
      50            1 :     active++;
      51              :   }
      52            1 :   if (active == 0) return result;
      53            2 :   for (var d = 0; d < hiddenDim; d++) {
      54            2 :     result[d] /= active;
      55              :   }
      56              :   return result;
      57              : }
      58              : 
      59              : /// L2-normalises [vec] in-place and returns it.
      60              : ///
      61              : /// After normalisation the vector has unit length (norm ≈ 1.0). This is
      62              : /// required before SQ8 quantisation (the fixed range [-1, 1] assumes
      63              : /// L2-normalised input) and before computing cosine similarity as a dot
      64              : /// product.
      65              : ///
      66              : /// If [vec] is a zero vector (norm = 0) it is returned unchanged to avoid
      67              : /// division by zero.
      68            1 : Float32List l2Normalize(Float32List vec) {
      69              :   var norm = 0.0;
      70            2 :   for (final v in vec) {
      71            2 :     norm += v * v;
      72              :   }
      73            1 :   norm = sqrt(norm);
      74            1 :   if (norm == 0.0) return vec;
      75            3 :   for (var i = 0; i < vec.length; i++) {
      76            2 :     vec[i] /= norm;
      77              :   }
      78              :   return vec;
      79              : }
      80              : 
      81              : /// Computes the cosine similarity (dot product) of two L2-normalised vectors.
      82              : ///
      83              : /// For unit-norm vectors `a` and `b`, the cosine similarity equals their dot
      84              : /// product, which is in the range `[-1.0, 1.0]`. In practice BGE embeddings
      85              : /// tend to give scores in `[0.0, 1.0]` for English text.
      86              : ///
      87              : /// [a] and [b] must have the same length.
      88            1 : double cosineSimilarity(Float32List a, Float32List b) {
      89            4 :   assert(a.length == b.length, 'Vectors must have the same length');
      90              :   var dot = 0.0;
      91            3 :   for (var i = 0; i < a.length; i++) {
      92            4 :     dot += a[i] * b[i];
      93              :   }
      94              :   return dot;
      95              : }
        

Generated by: LCOV version 2.0-1