using System; namespace ZeroLevel.HNSW.Services { public class Quantizator { private readonly float _min; private readonly float _max; private readonly float _diff; public Quantizator(float min, float max) { _min = min; _max = max; _diff = _max - _min; } public byte[] Quantize(float[] v) { var result = new byte[v.Length]; for (int i = 0; i < v.Length; i++) { result[i] = _quantizeInRange(v[i]); } return result; } public int[] QuantizeToInt(float[] v) { if (v.Length % 4 != 0) { throw new ArgumentOutOfRangeException("v.Length % 4 must be zero!"); } var result = new int[v.Length / 4]; byte[] buf = new byte[4]; for (int i = 0; i < v.Length; i += 4) { buf[0] = _quantizeInRange(v[i]); buf[1] = _quantizeInRange(v[i + 1]); buf[2] = _quantizeInRange(v[i + 2]); buf[3] = _quantizeInRange(v[i + 3]); result[(i >> 2)] = BitConverter.ToInt32(buf); } return result; } public long[] QuantizeToLong(float[] v) { if (v.Length % 8 != 0) { throw new ArgumentOutOfRangeException("v.Length % 8 must be zero!"); } var result = new long[v.Length / 8]; byte[] buf = new byte[8]; for (int i = 0; i < v.Length; i += 8) { buf[0] = _quantizeInRange(v[i + 0]); buf[1] = _quantizeInRange(v[i + 1]); buf[2] = _quantizeInRange(v[i + 2]); buf[3] = _quantizeInRange(v[i + 3]); buf[4] = _quantizeInRange(v[i + 4]); buf[5] = _quantizeInRange(v[i + 5]); buf[6] = _quantizeInRange(v[i + 6]); buf[7] = _quantizeInRange(v[i + 7]); result[(i >> 3)] = BitConverter.ToInt64(buf); } return result; } //Map x in [0,1] to {0, 1, ..., 255} private byte _quantize(float x) { x = (int)Math.Floor(256 * x); if (x < 0) return 0; else if (x > 255) return 255; else return (byte)x; } //Map x in [min,max] to {0, 1, ..., 255} private byte _quantizeInRange(float x) { return _quantize((x - _min) / (_diff)); } } }