pyphysim.ia package

Submodules

pyphysim.ia.algorithms module

Module with implementation of Interference Alignment (IA) algorithms.

Note that all IA algorithms require the channel object and any change to the channel object must be performed before calling the solve method of the IA algorithm object. This includes generating the channel and setting the noise variance.

class pyphysim.ia.algorithms.AlternatingMinIASolver(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: pyphysim.ia.algorithms.IterativeIASolverBaseClass

Implements the “Interference Alignment via Alternating Minimization” algorithm from the paper with the same name [PetersHeathAltMin2009].

This algorithm is applicable to a “K-user” scenario and it is very flexible in the sense that you can change the number of transmit antennas, receive antennas and streams per user, as well as the number of users involved in the IA process. However, note that alignment is only feasible for some cases configurations.

An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.

You can determine the scenario of an AlternatingMinIASolver object by inferring the variables K, Nt, Nr and Ns.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

Notes

PetersHeathAltMin2009

Peters, S.W.; Heath, R.W., “Interference alignment via alternating minimization,” Acoustics, Speech and Signal Processing, 2009. ICASSP 2009. IEEE International Conference on, pp.2445,2448, 19-24 April 2009

_before_initialize_W_func()None[source]

Method run in any of the initialize methods after the precoder is initialized but before the receive filter is initialized.

_solve_finalize()None[source]

Perform any post processing after the solution has been found.

_step()None[source]

Performs one iteration of the algorithm.

The step method is usually all you need to call to perform an iteration of the Alternating Minimization algorithm. It will update C, then update F and finally update W.

_updateC()None[source]

Update the value of Ck for all K users.

Ck contains the orthogonal basis of the interference subspace of user k. It corresponds to the Nk-Sk dominant eigenvectors of

\(\sum_{l \neq k} \mtH_{k,l} \mtF_l \mtF_l^H \mtH_{k,l}^H\).

Notes

This method is called in the _step() method.

See also

_step()

_updateF()None[source]

Update the value of the precoder of all K users.

Fl, the precoder of the l-th user, tries avoid as much as possible to send energy into the desired signal subspace of the other users. Fl contains the Sl least dominant eigenvectors of \(\sum_{k \neq l} H_{k,l}^H (I - C_k C_k^H)H_{k,l}\)

Notes

This method is called in the _step() method.

See also

_step()

_updateW()None[source]

Update the zero-forcing filters.

The zero-forcing filter is calculated in the paper “MIMO Interference Alignment Over Correlated Channels with Imperfect CSI”.

Notes

This method is called in the _step() method.

See also

_step()

get_cost()float[source]

Get the Cost of the algorithm for the current iteration of the precoder.

Returns

cost – The Cost of the algorithm for the current iteration of the precoder. This is a real non-negative number.

Return type

float

property initialize_with

Get method for the initialize_with property.

class pyphysim.ia.algorithms.BruteForceStreamIASolver(iasolver_obj: pyphysim.ia.algorithms.IterativeIASolverBaseClass)[source]

Bases: object

Implements the Brute Force Stream Interference Alignment algorithm variation.

This is not a new IA algorithm, but rather a variation of existing IA algorithms. The idea is to use another IA algorithm to find the IA solution for each possible stream configuration (number of streams for each user) and keep the best one.

Note: IA algorithms can provide different performance for the same number of streams but with different initializations. To reduce this variability we set the initialization method to ‘svd’ (see ‘initialize_with’ property in the IterativeIASolverBaseClass class) so that the initialization is always the same.

Parameters

iasolver_obj (T <= IASolverBaseClass) – Must be an object of a derived class of IterativeIASolverBaseClass.

clear()None[source]

Clear the BruteForceStreamIASolver object.

property every_sum_capacity

Get method for the every_sum_capacity property.

Returns

Tuple containing the sum capacity for each stream combination in self.stream_combinations.

Return type

list

property runned_iterations

Get method for the runned_iterations property.

Returns

The number of runned iterations.

Return type

int

solve(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None)int[source]

Find the IA solution.

This method updates the ‘F’ and ‘W’ member variables.

Parameters
  • Ns (int | np.ndarray) – MAXIMUM number of streams of each user. All possible values from 1 to Ns (or Ns[k], if Ns is an array) will tried.

  • P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

Returns

Number of iterations the iterative interference alignment algorithm run.

Return type

int

property stream_combinations

Get method for the stream_combinations property.

Returns

Tuple containing every possible stream combination.

Return type

tuple

class pyphysim.ia.algorithms.ClosedFormIASolver(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix, use_best_init: bool = True)[source]

Bases: pyphysim.ia.iabase.IASolverBaseClass

Implements the closed form Interference Alignment algorithm as described in the paper “Interference Alignment and Degrees of Freedom of the K User Interference Channel [CadambeDoF2008]”.

Parameters
  • multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

  • use_best_init (bool) – If true, all possible initializations (subsets of the eigenvectors of the ‘E’ matrix)for the first precoder will be tested and the best solution will be used. If false, the first initialization will be used.

Notes

CadambeDoF2008

V. R. Cadambe and S. A. Jafar, “Interference Alignment and Degrees of Freedom of the K User Interference Channel,” IEEE Transactions on Information Theory 54, pp. 3425-3441, Aug. 2008.

_calc_E()numpy.ndarray[source]

Calculates the “E” matrix, given by

\(\mtE = \mtH_{31}^{-1}\mtH_{32}\mtH_{12}^{-1}\mtH_{13}\mtH_{23}^{-1}\mtH_{21}\).

Returns

The “E” matrix.

Return type

np.ndarray

_calc_all_F_initializations(Ns: int) → List[numpy.ndarray][source]

Calculates all possible initializations for the first precoder (self._F[0]).

The precoder self._F[0] is initialized with a subset of the eigenvectors of the matrix ‘E’. Therefore, this method returns all possible subsets of the eigenvectors of the matrix ‘E’.

Parameters

Ns (int) – Number of streams of the first user.

Returns

all_initializations – All possible subsets (with size Ns) of the eigenvectors of the matrix E

Return type

list[np.ndarray]

_updateF(F0: Optional[numpy.ndarray] = None)None[source]

Find the precoders.

Parameters

F0 (np.ndarray) – The first precoder. If not provided, the matrix ‘E’ will be calculated (with the _calc_E method) and the the first Ns eigenvectors will be used as F0.

_updateW()None[source]

Find the receive filters

solve(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None)None[source]

Find the IA solution.

This method updates the ‘F’ and ‘W’ member variables.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

class pyphysim.ia.algorithms.GreedStreamIASolver(iasolver_obj: Type[pyphysim.ia.iabase.IASolverBaseClass])[source]

Bases: object

Implements the Greed Stream Interference Alignment algorithm variation.

This is not a new IA algorithm, but rather a variation of existing IA algorithms. The idea is to use another IA algorithm to find the IA solution for the desired maximum number of streams. After the solution is found, we remove the worst stream and use the same algorithm again to find a new solution. If the solution after the stream reduction provided a larger sum capacity we remove the worst stream again and keep going until each user has only one stream or the sum capacity after stream reduction is lower. The final solution will be for the number of streams that yielded the largest sum capacity.

Parameters

iasolver_obj (T <= IASolverBaseClass) – Must be an object of a derived class of IterativeIASolverBaseClass.

_find_index_stream_with_worst_sinr() → Tuple[int, int][source]

Considering the current solution (precoders and receive filters) in self._iasolver, find the index of the user and stream corresponding to the worst SINR.

Returns

  • user_idx (int) – The index of the user that has the stream with the worst SINR.

  • stream_idx (int) – The index of the stream (for user user_idx) with the worst SINR.

property runned_iterations

Get method for the runned_iterations property.

Returns

The number of runned iterations.

Return type

int

solve(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None)int[source]

Find the IA solution.

This method updates the ‘F’ and ‘W’ member variables.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

Returns

Number of iterations the iterative interference alignment algorithm run.

Return type

int

class pyphysim.ia.algorithms.IterativeIASolverBaseClass(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: pyphysim.ia.iabase.IASolverBaseClass

Base class for all Iterative IA algorithms.

All subclasses of IterativeIASolverBaseClass must implement at least the _updateF and _updateW methods.

Solving an iterative algorithm usually involves some initialization and then performing a “step” a given number of times until convergence. The initialization code is performed in the _solve_init method while the “step” corresponds to the _step method.

The initialization code is defined here as simply initializing the precoder with a random matrix and then calling the _updateW method (which must be implemented in a subclass) to update the receive filter. This is usually what you want but any subclass can redefine _solve_init if a different initialization is required.

The “step” part usually involves updating the precoder and then updating the receive filters. The definition of _step here calls two methods that MUST be defined in subclasses, the _updateF method and the _updateW method. If anything else is required in the “step” part then the _step method can be redefined in a subclass, but even in that case it should call the _updateF and _updateW methods instead of implementing everything in your redefined _step method.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

_before_initialize_W_func()None[source]

Method run in any of the initialize methods after the precoder is initialized but before the receive filter is initialized.

_dont_initialize_F_and_only_and_find_W(*_: Any)None[source]

Initialize the IA Solution from a random matrix.

The implementation here simple initializes the precoder variable and then calculates the initial receive filter.

Note: The dummy1 and dummy2 arguments have no effect. They only exist to keep the signature of this method equal to the signature of other initialize methods.

_initialize_F_and_W_from_alt_min(Ns: IntOrIntSequence, P: numpy.ndarray)None[source]

Initialize the IA Solution from the Alternating Minimizations IA solver.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

_initialize_F_and_W_from_closed_form(Ns: IntOrIntSequence, P: numpy.ndarray)None[source]

Initialize the IA Solution from the closed form IA solver.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

_initialize_F_randomly_and_find_W(Ns: Sequence[int], P: numpy.ndarray)None[source]

Initialize the IA Solution from a random matrix.

The implementation here simple initializes the precoder variable and then calculates the initial receive filter.

Parameters
  • Ns (int np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

_initialize_F_with_svd_and_find_W(Ns: IntOrIntSequence, P: numpy.ndarray)None[source]

Initialize the IA Solution from the most significant singular vectors of each user’s channel.

The implementation here simple initializes the precoder variable of each user as the most significant singular vector(s) of that user. After that, calculate the initial receive filters.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

classmethod _is_diff_significant(F_old: numpy.ndarray, F_new: numpy.ndarray, relative_factor: float)bool[source]

Test if there was any significant change from F_old to F_new.

This method is used internally in the solve method of the IterativeIASolverBaseClass to detect when the precoder of a given iteration didn’t change significantly from one iteration to another. This is used to stop the iterations of the algorithm and avoid unnecessary computations.

Parameters
  • F_old (np.ndarray) – The precoder of all users (in a previous iteration). This is a 1D numpy array of numpy arrays.

  • F_new (np.ndarray) – The precoder of all users (in the current iteration). This is a 1D numpy array of numpy arrays.

  • relative_factor (float) – Relative change of the precoder in one iteration to the next one. If the relative change from one iteration to the next one is lower than this factor then the algorithm will stop the iterations before the max_iterations limit is reached.

Returns

out – True if the difference is significant, False otherwise.

Return type

bool

Notes

A difference is considered significant if it is larger then 1/1000 of the minimum value in the precoder.

_solve_finalize()None[source]

Perform any post processing after the solution has been found.

Some of the found precoders may be a singular matrix. In that case, we need to remove the dimensions with zero energy from both the found precoder and the receive filter.

_solve_init(Ns: IntOrIntSequence, P: FloatOrFloatSequence)None[source]

Code run in the solve method before the loop that run the _step() method.

The implementation here simple initializes the precoder variable and then calculates the initial receive filter.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (float | np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

_step()None[source]

Performs one iteration of the algorithm.

This method does not return anything, but instead updates the precoder and receive filter.

abstract _updateF()None[source]

Update the precoders.

Notes

This method should be implemented in the derived classes

See also

_step()

abstract _updateW()None[source]

Update the receive filters.

Notes

This method should be implemented in the derived classes

See also

_step()

clear()None[source]

Clear the IA Solver object.

All member attributes that are updated during the solve method, such as the precoder and receive filters, will be cleared. The other attributes that correspond to “configuration” such as the channel object won’t be changed

Notes

You should overwrite this method in subclasses that pass parameters to the __init__ method, since here we call __init__ without arguments which is probably not what you want.

property initialize_with

Get method for the initialize_with property.

randomizeF(Ns: Union[int, List[int], Sequence[int]], P: Optional[numpy.ndarray] = None)None[source]

Generates a random precoder for each user.

Parameters
  • Ns (int | list[int] | np.ndarray) – Number of streams of each user.

  • P (np.ndarray, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

property runned_iterations

Get method for the runned_iterations property.

solve(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None)int[source]

Find the IA solution by performing the _step() method several times.

The number of times the _step() method is run is controlled by the max_iterations member variable.

Before calling the _step() method for the first time the _solve_init method is called to perform any required initializations. Since iterative IA algorithms usually starts with a random precoder then the _solve_init implementation in IterativeIASolverBaseClass calls randomizeF.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

Returns

  • Number of iterations that the iterative interference alignment

  • algorithm run.

Notes

You probably should not overwrite this method in sub-classes of the IterativeIASolverBaseClass. If you want to change the initialization of the algorithm overwrite the _solve_init method instead.

Subclasses must implement the _updateF() and _updateW() methods. If something else besides calling these two methods is required in the “step” part of the algorithm, then reimplement also the _step() method.

class pyphysim.ia.algorithms.MMSEIASolver(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: pyphysim.ia.algorithms.IterativeIASolverBaseClass

Implements the MMSE based Interference Alignment algorithm.

This algorithm is applicable to a “K-user” scenario and it is described in [Peters2011].

An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.

You can determine the scenario of an MMSEIASolver object by inferring the variables K, Nt, Nr and Ns.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

Notes

Peters2011

S. W. Peters and R. W. Heath, “Cooperative Algorithms for MIMO Interference Channels,” vol. 60, no. 1, pp. 206-218, 2011.

_calc_Uk(k: int)numpy.ndarray[source]

Calculates the receive filter of the k-th user.

Parameters

k (int) – User index

Returns

Uk – The receive filter of the user ‘k’.

Return type

np.ndarray

_calc_Vi(i: int, mu_i: Optional[float] = None)numpy.ndarray[source]

Calculates the precoder of the i-th user.

Parameters
  • i (int) – User index

  • mu_i (float, optional) – The value of the Lagrange multiplier. If it is None (default), then the best value will be found and used to calculate the precoder.

Returns

Vi – The calculate precoder of the i-th user.

Return type

np.ndarray

static _calc_Vi_for_a_given_mu(sum_term: numpy.ndarray, mu_i: float, H_herm_U: numpy.ndarray)numpy.ndarray[source]

Calculates the value of Vi for the given parameters.

This method is called inside _calc_Vi.

Parameters
  • sum_term (np.ndarray) – The summation term in the formula to calculate the precoder.

  • mu_i (float) – The value of the lagrange multiplier

  • H_herm_U (np.ndarray) – The value of \(H_ii^H U_i\)

Returns

The Vi matrix for the given parameters.

Return type

np.ndarray

static _calc_Vi_for_a_given_mu2(inv_sum_term: numpy.ndarray, mu_i: float, H_herm_U: numpy.ndarray)numpy.ndarray[source]

Calculates the value of Vi for the given parameters.

This method is called inside _calc_Vi.

Parameters
  • inv_sum_term (np.ndarray) – The inverse of the summation term in the formula to calculate the precoder when mu_i is equal to zero.

  • mu_i (float) – The value of the lagrange multiplier

  • H_herm_U (np.ndarray) – The value of \(H_ii^H U_i\)

Returns

The Vi matrix for the given parameters.

Return type

np.ndarray

_solve_init(Ns: IntOrIntSequence, P: numpy.ndarray)None[source]

Code run in the solve method before the loop that run the IterativeIASolverBaseClass._step() method.

The implementation here simple initializes the precoder variable and then calculates the initial receive filter.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

_updateF()None[source]

Updates the precoder of all users.

_updateW()None[source]

Updates the receive filter of all users.

class pyphysim.ia.algorithms.MaxSinrIASolver(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: pyphysim.ia.algorithms.IterativeIASolverBaseClass

Implements the “Interference Alignment via Max SINR” algorithm.

This algorithm is applicable to a “K-user” scenario and it is described in [Cadambe2008].

An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.

You can determine the scenario of an MaxSinrIASolver object by inferring the variables K, Nt, Nr and Ns.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

_calc_Bkl_cov_matrix_all_l_rev(k: int)numpy.ndarray[source]

Calculates the interference-plus-noise covariance matrix for all streams at “receiver” \(k\) for the reverse channel.

Parameters

k (int) – Index of the desired user.

Returns

Bkl_rev – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.

Return type

np.ndarray

_calc_Bkl_cov_matrix_first_part_rev(k: int)numpy.ndarray[source]

Calculates the first part in the equation of the Blk covariance matrix of the reverse channel.

Parameters

k (int) – Index of the desired user.

Returns

Bkl_first_part_rev – First part in equation (28) of [Cadambe2008], but for the reverse channel.

Return type

np.ndarray

_calc_Bkl_cov_matrix_second_part_rev(k: int, l: int)numpy.ndarray[source]

Calculates the second part in the equation of the Blk covariance matrix of the reverse channel..

The second part is given by

\(\frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger}\)

Parameters
  • k (int) – Index of the desired user.

  • l (int) – Index of the desired stream.

Returns

second_part – Second part in equation (28) of [Cadambe2008].

Return type

np.ndarray

classmethod _calc_Uk(Hkk: numpy.ndarray, Vk: numpy.ndarray, Bkl_all_l: numpy.ndarray)numpy.ndarray[source]

Similar to the _calc_Ukl() method, but while _calc_Ukl() calculates the receive filter (a vector) only for the \(l\)-th stream _calc_Uk() calculates a receive filter (a matrix) for all streams.

Parameters
  • Hkk (np.ndarray) – Channel from transmitter K to receiver K.

  • Vk (np.ndarray) – Precoder of user k.

  • Bkl_all_l (np.ndarray) – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.

Returns

Uk – The receive filter for all streams of user k.

Return type

np.ndarray

_calc_Uk_all_k()numpy.ndarray[source]

Calculates the receive filter of all users.

Returns

The receive filter of all users. This is a numpy array of numpy arrays.

Return type

np.ndarray

_calc_Uk_all_k_rev()numpy.ndarray[source]

Calculates the receive filter of all users for the reverse channel.

Returns

np.ndarray

The receive filter of all users for the reverse channel. This is a numpy array of numpy arrays.

classmethod _calc_Ukl(Hkk: numpy.ndarray, Vk: numpy.ndarray, Bkl: numpy.ndarray, l: int)numpy.ndarray[source]

Calculates the Ukl matrix in equation (29) of [Cadambe2008].

Parameters
  • Hkk (np.ndarray) – Channel from transmitter K to receiver K.

  • Vk (np.ndarray) – Precoder of user k.

  • Bkl (np.ndarray) – The previously calculates Bkl matrix in equation (28) of [Cadambe2008]

  • l (int) – Index of the desired stream

Returns

Ukl – The calculated Ukl matrix. This is a 2D numpy array (with self.Nr[k] rows and a single column).

Return type

np.ndarray

_updateF()None[source]

Update the precoders.

Notes

This method is called in the IterativeIASolverBaseClass._step() method.

_updateW()None[source]

Update the receive filters.

Notes

This method is called in the IterativeIASolverBaseClass._step() method.

class pyphysim.ia.algorithms.MinLeakageIASolver(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: pyphysim.ia.algorithms.IterativeIASolverBaseClass

Implements the Minimum Leakage Interference Alignment algorithm as described in the paper “Approaching the Capacity of Wireless Networks through Distributed Interference Alignment [Cadambe2008]”.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

_calc_Uk_all_k()numpy.ndarray[source]

Calculates the receive filter of all users.

Returns

The Uk array of each user. This is a 1D numpy array of numpy arrays.

Return type

np.ndarray

_calc_Uk_all_k_rev()numpy.ndarray[source]

Calculates the receive filter of all users in the reverse network.

Returns

The Uk array of each user. This is a 1D numpy array of numpy arrays.

Return type

np.ndarray

_updateF()None[source]

Update the precoders.

Notes

This method is called in the IterativeIASolverBaseClass._step() method.

_updateW()None[source]

Update the receive filters.

Notes

This method is called in the IterativeIASolverBaseClass._step() method.

get_cost()float[source]

Get the Cost of the algorithm for the current iteration of the precoder.

For the Minimum Leakage Interference Alignment algorithm the cost is equivalent to the sum of the interference that all users see after applying the receive filter. That is,

\(C = Tr[\mtU_k^H \mtQ_k \mtU_k]\)

Returns

cost – The Cost of the algorithm for the current iteration of the precoder. This is a (real non-negative number).

Return type

float

pyphysim.ia.iabase module

Module containing the base class for Interference Alignment (IA) Algorithms.

This module should probably only be imported in the other modules inside the ‘ia’ package that implement the IA algorithms.

class pyphysim.ia.iabase.IASolverBaseClass(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]

Bases: object

Base class for all Interference Alignment Algorithms.

At least the _updateW, _updateF and solve methods must be implemented in the subclasses of IASolverBaseClass, where the solve method uses the _updateW and _updateF methods in its implementation.

The implementation of the _updateW method should call the _clear_receive_filter method in the beginning and after that set either the _W or the _W_H variables with the correct value.

The implementation of the _updateF method should call the clear_precoder_filter in the beginning and after that set _W variable with the correct precoder (normalized to have a Frobenius norm equal to one.

The implementation of the _updateF method must set the _F variable with the correct value.

Another method that can be implemented is the get_cost method. It should return the cost of the current IA solution. What is considered “the cost” varies from one IA algorithm to another, but should always be a real non-negative number. If get_cost is not implemented a value of -1 is returned.

Parameters

multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.

property F

Transmit precoder of all users.

Returns

The precoders of all users (a 1D numpy array of 2D numpy arrays).

Return type

np.ndarray

property K

The number of users.

Returns

K – The number of users.

Return type

int

property Nr

Number of receive antennas of all users.

Returns

Nr – Number of receive antennas of all users.

Return type

np.ndarray

property Ns

Number of streams of all users.

Returns

Ns – Number of streams of all users.

Return type

np.ndarray

property Nt

Number of transmit antennas of all users.

Returns

Nt – Number of transmit antennas of all users.

Return type

np.ndarray

property P

Transmit power of all users.

Returns

The power of all users.

Return type

np.ndarray

property W

Receive filter of all users.

Returns

The receive filter of all users. (a 1D numpy array of 2D numpy arrays).

Return type

np.ndarray

property W_H

Get method for the W_H property.

Returns

The conjugate of the receive filter of all users. (a 1D numpy array of 2D numpy arrays).

Return type

np.ndarray

_calc_Bkl_cov_matrix_all_l(k: int, noise_power: Optional[float] = None)numpy.ndarray[source]

Calculates the interference-plus-noise covariance matrix for all streams at receiver \(k\) according to equation (28) in [Cadambe2008].

The interference-plus-noise covariance matrix for stream \(l\) of user \(k\) is given by Equation (28) in [Cadambe2008], which is reproduced below

\[\mtB^{[kl]} = \sum_{j=1}^{K} \frac{P^{[j]}}{d^{[j]}} \sum_{d=1}^{d^{[j]}} \mtH^{[kj]}\mtV_{\star l}^{[j]} \mtV_{\star l}^{[j]\dagger} \mtH^{[kj]\dagger} - \frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger} + \mtI_{N^{[k]}}\]

where \(P^{[k]}\) is the transmit power of transmitter \(k\), \(d^{[k]}\) is the number of degrees of freedom of user \(k\), \(\mtH^{[kj]}\) is the channel between transmitter \(j\) and receiver \(k\), \(\mtV_{\star l}\) is the \(l\)-th column of the precoder of user \(k\) and \(\mtI_{N^{k}}\) is an identity matrix with size equal to the number of receive antennas of receiver \(k\).

Parameters
  • k (int) – Index of the desired user.

  • noise_power (float) – Noise power (variance).

Returns

Bkl – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.

Return type

np.ndarray

Notes

To be simple, a function that returns the covariance matrix of only a single stream “l” of the desired user “k” could be implemented, but in the order to calculate the max SINR algorithm we need the covariance matrix of all streams and returning them in single function as is done here allows us to calculate the first part in equation (28) of [Cadambe2008] only once, since it is the same for all streams.

_calc_Bkl_cov_matrix_first_part(k: int)numpy.ndarray[source]

Calculates the first part in the equation of the Blk covariance matrix in equation (28) of [Cadambe2008].

The first part is given by

\[\sum_{j=1}^{K} \frac{P^{[j]}}{d^{[j]}} \sum_{d=1}^{d^{[j]}} \mtH^{[kj]}\mtV_{\star d}^{[j]} \mtV_{\star d}^{[j]\dagger} \mtH^{[kj]\dagger}\]

Note that it only depends on the value of \(k\).

Parameters

k (int) – Index of the desired user.

Returns

Bkl_first_part – First part in equation (28) of [Cadambe2008].

Return type

np.ndarray

_calc_Bkl_cov_matrix_second_part(k: int, l: int)numpy.ndarray[source]

Calculates the second part in the equation of the Blk covariance matrix in equation (28) of [Cadambe2008] (note that it does not include the identity matrix).

The second part is given by

\[\frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger}\]
Parameters
  • k (int) – Index of the desired user.

  • l (int) – Index of the desired stream.

Returns

second_part – Second part in equation (28) of [Cadambe2008].

Return type

np.ndarray

_calc_SINR_k(k: int, Bkl_all_l: Sequence[numpy.ndarray])numpy.ndarray[source]

Calculates the SINR of all streams of user ‘k’.

Parameters
  • k (int) – Index of the desired user.

  • Bkl_all_l (list[np.ndarray] | nd.ndarray) – A sequence (1D numpy array, a list, etc) of 2D numpy arrays corresponding to the Bkl matrices for all ‘l’s.

Returns

SINR_k – The SINR for the different streams of user k.

Return type

np.ndarray

_calc_equivalent_channel(k: int)numpy.ndarray[source]

Calculates the equivalent channel for user \(k\) considering the effect of the precoder (including transmit power), the actual channel, and the receive filter (without power compensation).

Parameters

k (int) – The index of the desired user.

Returns

Hk_eq – The equivalent channel.

Return type

np.ndarray

Notes

This method is used only internally in order to calculate the “W” get property so that the returned filter W compensates the effect of the direct channel.

_clear_precoder_filter()None[source]

Clear the precoder filter.

This should be called in the beginning of the implementation of the _updateF method in subclasses.

_clear_receive_filter()None[source]

Clear the receive filter.

This should be called in the beginning of the implementation of the _updateW method in subclasses.

_get_channel(k: int, l: int)numpy.ndarray[source]

Get the channel from transmitter l to receiver k.

Parameters
  • l (int) – Transmitting user.

  • k (int) – Receiving user.

Returns

H – The channel matrix between transmitter l and receiver k.

Return type

np.ndarray

_get_channel_rev(k: int, l: int)numpy.ndarray[source]

Get the channel from transmitter l to receiver k in the reverse network.

Let the matrix \(\mtH_{kl}\) be the channel matrix between the transmitter \(l\) to receiver \(k\) in the direct network. The channel matrix between the transmitter \(l\) to receiver \(k\) in the reverse network, denoted as \(\overleftarrow{\mtH}_{kl}\), is then given by \(\overleftarrow{\mtH}_{kl} = \mtH_{lk}^\dagger\) where \(\mtA^\dagger\) is the conjugate transpose of \(\mtA\).

Parameters
  • l (int) – Transmitting user of the reverse network.

  • k (int) – Receiving user of the reverse network.

Returns

H – The channel matrix between transmitter l and receiver k in the reverse network.

Return type

np.ndarray

Notes

See Section III of [Cadambe2008] for details.

calc_Q(k: int)numpy.ndarray[source]

Calculates the interference covariance matrix at the \(k\)-th receiver.

The interference covariance matrix at the \(k\)-th receiver, \(\mtQ k\), is given by

\[\mtQ k = \sum_{j=1, j \neq k}^{K} \frac{P_j}{Ns_j} \mtH_{kj} \mtF_j \mtF_j^H \mtH_{kj}^H\]

where \(P_j\) is the transmit power of transmitter \(j\), and \(Ns_j\) is the number of streams for user \(j\).

Parameters

k (int) – Index of the desired receiver.

Returns

Qk – The interference covariance matrix at receiver \(k\).

Return type

np.ndarray

Notes

This is impacted by the self.P attribute.

calc_Q_rev(k: int)numpy.ndarray[source]

Calculates the interference covariance matrix at the \(k\)-th receiver in the reverse network.

Parameters

k (int) – Index of the desired receiver.

Returns

Qk_rev – The interference covariance matrix at receiver \(k\) in the reverse network.

Return type

np.ndarray

See also

calc_Q()

calc_SINR()numpy.ndarray[source]

Calculates the SINR values (in linear scale) of all streams of all users with the current IA solution.

The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.

Returns

SINRs – The SINR (in linear scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).

Return type

np.ndarray

calc_SINR_in_dB()numpy.ndarray[source]

Calculates the SINR values (in dB scale) of all streams of all users with the current IA solution.

The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.

Returns

SINRs – The SINR (in dB scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).

Return type

np.ndarray

calc_SINR_old()numpy.ndarray[source]

Calculates the SINR values (in linear scale) of all streams of all users with the current IA solution.

The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.

This method is deprecated since it’s not the correct way to calculate the SINR. Use the calc_SINR method instead.

Returns

SINRs – The SINR (in linear scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).

Return type

np.ndarray

calc_remaining_interference_percentage(k: int, Qk: Optional[numpy.ndarray] = None)float[source]

Calculates the percentage of the interference in the desired signal space according to equation (30) in [Cadambe2008].

The percentage \(p_k\) of the interference in the desired signal space is given by

\[p_k = \frac{\sum_{j=1}^{Ns[k]} \lambda_j [\mtQ k]}{Tr[\mtQ k]}\]

where \(\lambda_j[\mtA]\) denotes the \(j\)-th smallest eigenvalue of \(\mtA\).

Parameters
  • k (int) – The index of the desired user.

  • Qk (np.ndarray) – The covariance matrix of the remaining interference at receiver k. If not provided, it will be automatically calculated. In that case, the P attribute will also be taken into account if it is set.

Returns

The percentage of the interference in the desired signal space.

Return type

float

Notes

Qk must be a symmetric matrix so that its eigenvalues are real and positive (any covariance matrix is a symmetric matrix).

calc_sum_capacity()float[source]

Calculates the sum capacity of the current solution.

The SINRs are estimated and applied to the Shannon capacity formula

Returns

The sum capacity of the current solution.

Return type

float

clear()None[source]

Clear the IA Solver object.

All member attributes that are updated during the solve method, such as the precoder and receive filters, will be cleared. The other attributes that correspond to “configuration” such as the channel object won’t be changed.

Notes

You should overwrite this method in subclasses that pass parameters to the __init__ method, since here we call __init__ without arguments which is probably not what you want.

property full_F

Transmit precoder of all users.

Returns

The precoders of all users (a 1D numpy array of 2D numpy arrays).

Return type

np.ndarray

property full_W

Get method for the full_W property.

The full_W property returns the equivalent filter of the IA filter plus the post processing filter.

Returns

the equivalent filter of the IA filter plus the post processing filter.

Return type

np.ndarray

property full_W_H

Get method for the full_W_H property.

The full_W_H property returns the equivalent filter of the IA filter plus the post processing filter.

Returns

The equivalent filter of the IA filter plus the post processing filter.

Return type

np.ndarray

get_cost()float[source]

Get the current cost of the IA Solution.

This method should be implemented in subclasses and return a number greater than or equal to zero..

Returns

cost – The Cost of the current IA solution (a real non-negative number).

Return type

float

property noise_var

Get method for the noise_var property.

Returns

The noise variance (a real non-negative number).

Return type

float

randomizeF(Ns: Union[int, List[int], Sequence[int]], P: Optional[numpy.ndarray] = None)None[source]

Generates a random precoder for each user.

Parameters
  • Ns (int | list[int] | np.ndarray) – Number of streams of each user.

  • P (np.ndarray, optional) – Power of each user. If not provided, a value of 1 will be used for each user.

set_precoders(F: Optional[Sequence[numpy.ndarray]] = None, full_F: Optional[Sequence[numpy.ndarray]] = None, P: Optional[numpy.ndarray] = None)None[source]

Set the precoders of each user.

Either F or full_F (or both of them) must be provided.

If only full_F is provided then the value of F will be calculated from full_F.

In any case, the value of self.Ns will be updated according to the dimensions of the F or full_F.

Parameters
  • F (np.ndarray | list[np.ndarray], optional) – A numpy array where each element is the (normalized) precoder (a 2D numpy array) of one user.

  • full_F (np.ndarray | list[np.ndarray], optional) – A numpy array where each element is the precoder (a 2D numpy array) of one user.

  • P (np.ndarray, optional) – The maximum transmit power. If not provided the current value of self.P will be kept as it is.

set_receive_filters(W_H: Optional[Sequence[numpy.ndarray]] = None, W: Optional[Sequence[numpy.ndarray]] = None)None[source]

Set the receive filters.

You only need to pass either W_H or W, but not both of them, since one is calculated from the other.

Parameters
  • W_H (np.ndarray | list[np.ndarray]) – A numpy array where each element is the receive filter (a 2D numpy array) of one user. This is a 1D numpy array of 2D numpy arrays.

  • W (np.ndarray | list[np.ndarray]) – A numpy array where each element is the receive filter (a 2D numpy array) of one user. This is a 1D numpy array of 2D numpy arrays.

abstract solve(Ns: Union[int, numpy.ndarray], P: Optional[numpy.ndarray] = None) → Any[source]

Find the IA solution.

This method must be implemented in a subclass and should updates the ‘F’ and ‘W’ member variables.

Parameters
  • Ns (int | np.ndarray) – Number of streams of each user.

  • P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.

Notes

This function should be implemented in the derived classes

Module contents

Package with Interference Alignment (IA) algorithms.

Note that all IA algorithms require the channel object and any change to the channel object must be performed before calling the solve method of the IA algorithm object. This includes generating the channel and setting the noise variance.