Skip to content

Commit 61508e4

Browse files
committed
Standardize bit for spin
1 parent b6a6f4b commit 61508e4

2 files changed

Lines changed: 88 additions & 91 deletions

File tree

dimod/generators/wireless.py

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525

2626
mod_params = namedtuple("mod_params", ["bits_per_transmitter",
2727
"amplitudes",
28-
"transmitters_per_spin",
28+
"transmitters_per_bit",
2929
"number_of_amps",
30-
"spins_per_symbol"])
30+
"bits_per_symbol"])
3131
mod_config = {
3232
"BPSK": mod_params(1, 1, 1, 1, 1),
3333
"QPSK": mod_params(2, 1, 2, 1, 1),
@@ -132,8 +132,8 @@ def _amplitude_modulated_quadratic_form(h, J, modulation="BPSK"):
132132
JA = np.kron(np.kron(amps[:, np.newaxis], amps[np.newaxis, :]), J)
133133
return hA, JA
134134

135-
def _symbols_to_spins(symbols, modulation="BPSK"):
136-
"""Convert quadrature amplitude modulated (QAM) symbols to spins.
135+
def _symbols_to_bits(symbols, modulation="BPSK"):
136+
"""Convert quadrature amplitude modulated (QAM) symbols to bits.
137137
138138
Args:
139139
symbols: Transmitted symbols as a NumPy column vector.
@@ -143,7 +143,7 @@ def _symbols_to_spins(symbols, modulation="BPSK"):
143143
quadrature modulations 'QPSK', '16QAM', '64QAM', and '256QAM'.
144144
145145
Returns:
146-
Spins as a NumPy array.
146+
Bits as a NumPy array.
147147
"""
148148
if modulation not in mod_config:
149149
raise ValueError(f"Unsupported modulation: {modulation}")
@@ -154,25 +154,25 @@ def _symbols_to_spins(symbols, modulation="BPSK"):
154154
if modulation == 'QPSK':
155155
return np.concatenate((symbols.real, symbols.imag))
156156

157-
spins_per_real_symbol = mod_config[modulation].spins_per_symbol
157+
bits_per_real_symbol = mod_config[modulation].bits_per_symbol
158158

159159
# A map from integer parts to real is clearest (and sufficiently performant),
160160
# generalizes to Gray coding more easily as well:
161161

162-
symb_to_spins = {np.sum([x * 2**xI for xI, x in enumerate(spins)]): spins
163-
for spins in product(*spins_per_real_symbol * [(-1, 1)])}
164-
spins = np.concatenate(
165-
[np.concatenate(([symb_to_spins[symb][prec] for symb in symbols.real.flatten()],
166-
[symb_to_spins[symb][prec] for symb in symbols.imag.flatten()]))
167-
for prec in range(spins_per_real_symbol)])
162+
symb_to_bits = {np.sum([x * 2**xI for xI, x in enumerate(bits)]): bits
163+
for bits in product(*bits_per_real_symbol * [(-1, 1)])}
164+
bits = np.concatenate(
165+
[np.concatenate(([symb_to_bits[symb][prec] for symb in symbols.real.flatten()],
166+
[symb_to_bits[symb][prec] for symb in symbols.imag.flatten()]))
167+
for prec in range(bits_per_real_symbol)])
168168

169169
if len(symbols.shape) > 2:
170170
raise ValueError(f"`symbols` should be 1 or 2 dimensional but is shape {symbols.shape}")
171171

172172
if symbols.ndim == 1: # If symbols shaped as vector, return as vector
173-
spins.reshape((len(spins), ))
173+
bits.reshape((len(bits), ))
174174

175-
return spins
175+
return bits
176176

177177
def _yF_to_hJ(y, F, modulation="BPSK"):
178178
"""Convert :math:`O(v) = ||y - F v||^2` to modulated quadratic form.
@@ -206,13 +206,13 @@ def _yF_to_hJ(y, F, modulation="BPSK"):
206206

207207
return h, J, offset
208208

209-
def _spins_to_symbols(spins,
209+
def _bits_to_symbols(bits,
210210
modulation="BPSK",
211211
num_transmitters=None):
212-
"""Convert spins to modulated symbols.
212+
"""Convert bits to modulated symbols.
213213
214214
Args:
215-
spins: Spins as a NumPy array.
215+
bits: Bits as a NumPy array.
216216
217217
modulation: Modulation. Supported values are the default non-quadrature
218218
modulation, 'BPSK', and quadrature modulations 'QPSK', '16QAM',
@@ -224,28 +224,28 @@ def _spins_to_symbols(spins,
224224
if modulation not in mod_config:
225225
raise ValueError(f"Unsupported modulation: {modulation}")
226226

227-
num_spins = len(spins)
227+
num_bits = len(bits)
228228

229229
if num_transmitters is None:
230-
num_transmitters = num_spins // mod_config[modulation].transmitters_per_spin
230+
num_transmitters = num_bits // mod_config[modulation].transmitters_per_bit
231231

232-
if num_transmitters == num_spins:
233-
symbols = spins
232+
if num_transmitters == num_bits:
233+
symbols = bits
234234
else:
235-
num_amps, rem = divmod(len(spins), (2*num_transmitters))
235+
num_amps, rem = divmod(len(bits), (2*num_transmitters))
236236
if num_amps > 64:
237237
raise ValueError('Complex encoding is limited to 64 bits in'
238238
'real and imaginary parts; `num_transmitters` is'
239239
'too small')
240240
if rem != 0:
241-
raise ValueError('number of spins must be divisible by `num_transmitters` '
241+
raise ValueError('number of bits must be divisible by `num_transmitters` '
242242
'for modulation schemes')
243243

244-
spinsR = np.reshape(spins, (num_amps, 2 * num_transmitters))
244+
bitsR = np.reshape(bits, (num_amps, 2 * num_transmitters))
245245
amps = 2 ** np.arange(0, num_amps)[:, np.newaxis]
246246

247-
symbols = np.sum(amps*spinsR[:, :num_transmitters], axis=0) \
248-
+ 1j*np.sum(amps*spinsR[:, num_transmitters:], axis=0)
247+
symbols = np.sum(amps*bitsR[:, :num_transmitters], axis=0) \
248+
+ 1j*np.sum(amps*bitsR[:, num_transmitters:], axis=0)
249249

250250
return symbols
251251

@@ -322,9 +322,6 @@ def create_channel(num_receivers: int = 1,
322322
attenuation_matrix: Optional[np.ndarray] = None) -> Tuple[np.ndarray, float]:
323323
"""Create a channel model.
324324
325-
Channel power is the expected mean-square signal amplification per receiver (i.e.,
326-
:math:`mean(F^2)*num_transmitters`) for homogeneous codes.
327-
328325
Args:
329326
num_receivers: Number of receivers.
330327
@@ -562,7 +559,7 @@ def mimo(modulation: Literal["BPSK", "QPSK", "16QAM", "64QAM", "256QAM"] = "BPSK
562559
subject to additive white Gaussian noise. Given the received signal,
563560
:math:`y`, the log likelihood of a given symbol set, :math:`v`, is
564561
:math:`MLE = argmin || y - F v ||_2`. When :math:`v` is encoded as
565-
a linear sum of spins, the optimization problem is a binary quadratic model.
562+
a linear sum of bits, the optimization problem is a binary quadratic model.
566563
567564
Depending on its parameters, this function can model code division multiple
568565
access (CDMA) _[#T02, #R20], 5G communication networks _[#Prince], or
@@ -582,16 +579,16 @@ def mimo(modulation: Literal["BPSK", "QPSK", "16QAM", "64QAM", "256QAM"] = "BPSK
582579
583580
Quadrature Phase Shift Keying. Transmitted symbols are
584581
:math:`1+1j, 1-1j, -1+1j, -1-1j` normalized by
585-
:math:`\\frac{1}{\\sqrt{2}}`. spins are encoded as a real vector
582+
:math:`\\frac{1}{\\sqrt{2}}`. Bits are encoded as a real vector
586583
concatenated with an imaginary vector.
587584
588585
* '16QAM'
589586
590587
Each user is assumed to select independently from 16 symbols.
591588
The transmitted symbol is a complex value that can be encoded
592-
by two spins in the imaginary part and two spins in the real
593-
part. Highest precision real and imaginary spin vectors are
594-
concatenated to lower precision spin vectors.
589+
by two bits in the imaginary part and two bits in the real
590+
part. Highest precision real and imaginary bit vectors are
591+
concatenated to lower precision bit vectors.
595592
596593
* '64QAM'
597594
@@ -641,9 +638,9 @@ def mimo(modulation: Literal["BPSK", "QPSK", "16QAM", "64QAM", "256QAM"] = "BPSK
641638
respectively. Note that for correct analysis by some solvers, applying
642639
spin-reversal transforms may be necessary.
643640
644-
For QAM modulations, amplitude randomness affects likelihood in a
645-
non-trivial way. By default, symbols are chosen independently and
646-
identically distributed from the constellations.
641+
For QAM modulations such as 16QAM, amplitude randomness affects
642+
likelihood in a non-trivial way. By default, symbols are chosen
643+
independently and identically distributed from the constellations.
647644
648645
channel_noise: Channel noise as a NumPy array of complex values. Must
649646
be consistent with the number of receivers.
@@ -767,7 +764,7 @@ def coordinated_multipoint(lattice: 'networkx.Graph',
767764
subject to additive white Gaussian noise. Given the received signal,
768765
:math:`y`, the log likelihood of a given symbol set, :math:`v`, is
769766
:math:`MLE = argmin || y - F v ||_2`. When :math:`v` is encoded as
770-
a linear sum of spins, the optimization problem is a binary quadratic model.
767+
a linear sum of bits, the optimization problem is a binary quadratic model.
771768
772769
Args:
773770
lattice: Geometry, as a :class:`networkx.Graph`, defining
@@ -788,14 +785,14 @@ def coordinated_multipoint(lattice: 'networkx.Graph',
788785
* 'QPSK'
789786
Quadrature Phase Shift Keying. Transmitted symbols are
790787
:math:`1+1j, 1-1j, -1+1j, -1-1j` normalized by
791-
:math:`\\frac{1}{\\sqrt{2}}`. Spins are encoded as a real vector
788+
:math:`\\frac{1}{\\sqrt{2}}`. Bits are encoded as a real vector
792789
concatenated with an imaginary vector.
793790
* '16QAM'
794791
Each user is assumed to select independently from 16 symbols.
795792
The transmitted symbol is a complex value that can be encoded
796-
by two spins in the imaginary part and two spins in the real
797-
part. Highest precision real and imaginary spin vectors are
798-
concatenated to lower precision spin vectors.
793+
by two bits in the imaginary part and two bits in the real
794+
part. Highest precision real and imaginary bit vectors are
795+
concatenated to lower precision bit vectors.
799796
* '64QAM'
800797
A QPSK symbol set is generated and symbols are further amplitude
801798
modulated by an independently and uniformly distributed random
@@ -820,9 +817,9 @@ def coordinated_multipoint(lattice: 'networkx.Graph',
820817
respectively. Note that for correct analysis by some solvers,
821818
applying spin-reversal transforms may be necessary.
822819
823-
For QAM modulations, amplitude randomness affects likelihood in a
824-
non-trivial way. By default, symbols are chosen independently and
825-
identically distributed from the constellations.
820+
For QAM modulations such as 16QAM, amplitude randomness affects
821+
likelihood in a non-trivial way. By default, symbols are chosen
822+
independently and identically distributed from the constellations.
826823
827824
channel_noise: Channel noise as a complex value.
828825
@@ -896,7 +893,7 @@ def coordinated_multipoint(lattice: 'networkx.Graph',
896893

897894
return bqm
898895

899-
# Linear-filter functions. These are not used for spin-encoding MIMO problems
896+
# Linear-filter functions. These are not used for bit-encoding MIMO problems
900897
# and are maintained here for user convenience
901898

902899
def linear_filter(F, method='zero_forcing', SNRoverNt=float('Inf'), PoverNt=1):

0 commit comments

Comments
 (0)