WIP: define ConstellationPoints class, bidict class (by Basj @ SO), some refactoring, add gitignore

This commit is contained in:
2024-07-20 11:27:14 +02:00
parent 29b35f0d17
commit 679b883393
3 changed files with 390 additions and 68 deletions

View File

@@ -1,12 +1,11 @@
from const import gray_1d
import numpy as np
def _validate_integer(value, name):
def validate_int(value, name):
if not isinstance(value, int):
raise ValueError(f'{name} must be an integer')
def _validate_range(value, name, min_val=None, max_val=None):
def validate_range(value, name, min_val=None, max_val=None):
if max_val is not None and value > max_val:
raise ValueError(f'{name} must be \u2265 {max_val}')
if min_val is not None and value < min_val:
@@ -14,10 +13,10 @@ def _validate_range(value, name, min_val=None, max_val=None):
def gray_1d_input_validation(k, symbol):
_validate_integer(symbol, 'symbol')
_validate_integer(k, 'k')
_validate_range(k, 'k', min_val=1)
_validate_range(symbol, 'symbol', min_val=0, max_val=2**k-1)
validate_int(symbol, 'symbol')
validate_int(k, 'k')
validate_range(k, 'k', min_val=1)
validate_range(symbol, 'symbol', min_val=0, max_val=2**k-1)
def next_symbol(k, symbol):
@@ -28,25 +27,83 @@ def next_symbol(k, symbol):
def gray_2d_input_validation(n, m, symbol):
_validate_integer(n, 'n')
_validate_integer(m, 'm')
_validate_integer(symbol, 'symbol')
_validate_range(n, 'n', min_val=0)
min_m = 0 if n > 0 else 1
_validate_range(m, 'm', min_val=min_m)
_validate_range(symbol, 'symbol', min_val=0, max_val=2**(m+n)-1)
def gray_2d_handle_1d(n, m, symbol):
n,m,swapped = m,n,True if n == 0 else n,m,False # swap n and m if n is zero -> if only one > 0, it's n
if m == 0:
return (gray_1d(n, symbol),None) if swapped else (None,gray_1d(n, symbol))
else:
return None
validate_int(n, 'n')
validate_int(m, 'm')
validate_int(symbol, 'symbol')
validate_range(m, 'm', min_val=0)
validate_range(n, 'n', min_val=m)
validate_range(symbol, 'symbol', min_val=0, max_val=2**(m+n)-1)
def split_symbol(n, m, symbol):
bits = format(symbol, 'b').zfill(n+m)
symbol_i = int(bits[:n], 2)
symbol_q = int(bits[n:], 2)
return symbol_i,symbol_q
return symbol_i,symbol_q
def validate_intpow2(value, name):
exponent = np.log2(value)
if exponent != int(exponent):
raise ValueError(f'{name} must be an integer power of 2')
def validate_coords(constellation_dict):
# TODO validate all coords, not only first
# bit of a hack, only looking at first element
if not isinstance(temp:=next(iter(constellation_dict.values())), tuple) or not isinstance(temp[0], int):
raise ValueError('coords must be tuples of integers')
# https://www.ieee802.org/3/bn/public/nov13/prodan_3bn_02_1113.pdf
class bidict(dict):
'''
### Summary:
A bidirectional dictionary (bidict) that allows bidirectional mapping between keys and values.
### Explanation:
This class extends the functionality of a standard dictionary to maintain a bidirectional mapping between keys and values. It provides methods to set, delete items, and retrieve the inverse mapping efficiently.
### Methods:
- `__init__(*args, **kwargs)`: Initializes the bidict with optional initial key-value pairs.
- `__setitem__(key, value)`: Sets a key-value pair in the bidict, updating the inverse mapping.
- `__delitem__(key)`: Deletes a key-value pair from the bidict and updates the inverse mapping.
- `__repr__()`: Returns a string representation of the bidict instance.
### Attributes:
- `inverse`: A dictionary that stores the inverse mapping of values to keys.
### Returns:
- No explicit return value for methods. The bidict instance is modified in place.
### Raises:
- No specific exceptions are raised by the methods in this class.
### Source:
bidict by user 'Basj' at https://stackoverflow.com/a/21894086 (CC BY-SA 4.0)
'''
def __init__(self, *args, **kwargs):
super(bidict, self).__init__(*args, **kwargs)
self.inverse = {}
for key, value in self.items():
self.inverse.setdefault(value, []).append(key)
def __setitem__(self, key, value):
if key in self:
self.inverse[self[key]].remove(key)
super(bidict, self).__setitem__(key, value)
self.inverse.setdefault(value, []).append(key)
def __delitem__(self, key):
self.inverse.setdefault(self[key], []).remove(key)
if self[key] in self.inverse and not self.inverse[self[key]]:
del self.inverse[self[key]]
super(bidict, self).__delitem__(key)
def __repr__(self):
return f'<bidict @[{id(self)}]'