import numpy as np 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): 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: raise ValueError(f'{name} must be \u2264 {min_val}') def gray_1d_input_validation(k, symbol): 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): bits = format(symbol, 'b').zfill(k) b0 = int(bits[0]) new_symbol = int(bits[1:], 2) return b0,new_symbol def gray_2d_input_validation(n, m, symbol): 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 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'