diff options
| author | J08nY | 2025-10-25 16:07:31 +0200 |
|---|---|---|
| committer | J08nY | 2025-10-25 16:07:31 +0200 |
| commit | 4bf6a31c00a90cb5aea54c7a37c95f8f3413faaf (patch) | |
| tree | 3c6b81eb26563919eb927c7bf46ba38d59be0e9e /analysis/scalarmults/epare/prob_map.py | |
| parent | 1bf4c680fed1eab512e65ec6b7a0b4eb6ce8ca74 (diff) | |
| download | ECTester-4bf6a31c00a90cb5aea54c7a37c95f8f3413faaf.tar.gz ECTester-4bf6a31c00a90cb5aea54c7a37c95f8f3413faaf.tar.zst ECTester-4bf6a31c00a90cb5aea54c7a37c95f8f3413faaf.zip | |
Split common analysis help file into modules.
Diffstat (limited to 'analysis/scalarmults/epare/prob_map.py')
| -rw-r--r-- | analysis/scalarmults/epare/prob_map.py | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/analysis/scalarmults/epare/prob_map.py b/analysis/scalarmults/epare/prob_map.py new file mode 100644 index 0000000..eb96dda --- /dev/null +++ b/analysis/scalarmults/epare/prob_map.py @@ -0,0 +1,65 @@ +from dataclasses import dataclass +import hashlib + + +def hash_divisors(divisors: set[int]) -> bytes: + return hashlib.blake2b(str(sorted(divisors)).encode(), digest_size=8).digest() + + +@dataclass +class ProbMap: + """ + A ProbMap is a mapping from integers (base point order q) to floats (error probability for some scalar + multiplication implementation, i.e. Config). The probability map is constructed for a given set of + `divisors` (the base point orders q). Probability maps can be narrowed or merged. A narrowing restricts + the probability map to a smaller set of `divisors`. A merging takes another probability map using the + same divisor set and updates the probabilities to a weighted average of the two probability maps + (the weight is the number of samples). + """ + probs: dict[int, float] + divisors_hash: bytes + samples: int + + def __len__(self): + return len(self.probs) + + def __iter__(self): + yield from self.probs + + def __getitem__(self, i): + return self.probs[i] if i in self.probs else 0.0 + + def __contains__(self, item): + return item in self.probs + + def keys(self): + return self.probs.keys() + + def values(self): + return self.probs.values() + + def items(self): + return self.probs.items() + + def narrow(self, divisors: set[int]): + """Narrow the probability map to the new set of divisors (must be a subset of the current set).""" + divisors_hash = hash_divisors(divisors) + if self.divisors_hash == divisors_hash: + # Already narrow. + return + for kdel in set(self.probs.keys()).difference(divisors): + del self.probs[kdel] + self.divisors_hash = divisors_hash + + def merge(self, other: "ProbMap") -> None: + """Merge the `other` probability map into this one (must share the divisor set).""" + if self.divisors_hash != other.divisors_hash: + raise ValueError("Merging can only work on probmaps created for same divisors.") + new_keys = set(self.keys()).union(other.keys()) + result = {} + for key in new_keys: + sk = self[key] + ok = other[key] + result[key] = (sk * self.samples + ok * other.samples) / (self.samples + other.samples) + self.probs = result + self.samples += other.samples
\ No newline at end of file |
