r"""Estimate feasible values for 0-weighted dual potentials The feasible values are computed efficiently but rather coarsely. .. warning:: This function is necessary because the C++ solver in `emd_c` discards all samples in the distributions with zeros weights. This
(alpha0, beta0, a, b, M)
| 78 | |
| 79 | |
| 80 | def estimate_dual_null_weights(alpha0, beta0, a, b, M): |
| 81 | r"""Estimate feasible values for 0-weighted dual potentials |
| 82 | |
| 83 | The feasible values are computed efficiently but rather coarsely. |
| 84 | |
| 85 | .. warning:: |
| 86 | This function is necessary because the C++ solver in `emd_c` |
| 87 | discards all samples in the distributions with |
| 88 | zeros weights. This means that while the primal variable (transport |
| 89 | matrix) is exact, the solver only returns feasible dual potentials |
| 90 | on the samples with weights different from zero. |
| 91 | |
| 92 | First we compute the constraints violations: |
| 93 | |
| 94 | .. math:: |
| 95 | \mathbf{V} = \alpha + \beta^T - \mathbf{M} |
| 96 | |
| 97 | Next we compute the max amount of violation per row (:math:`\alpha`) and |
| 98 | columns (:math:`beta`) |
| 99 | |
| 100 | .. math:: |
| 101 | \mathbf{v^a}_i = \max_j \mathbf{V}_{i,j} |
| 102 | |
| 103 | \mathbf{v^b}_j = \max_i \mathbf{V}_{i,j} |
| 104 | |
| 105 | Finally we update the dual potential with 0 weights if a |
| 106 | constraint is violated |
| 107 | |
| 108 | .. math:: |
| 109 | \alpha_i = \alpha_i - \mathbf{v^a}_i \quad \text{ if } \mathbf{a}_i=0 \text{ and } \mathbf{v^a}_i>0 |
| 110 | |
| 111 | \beta_j = \beta_j - \mathbf{v^b}_j \quad \text{ if } \mathbf{b}_j=0 \text{ and } \mathbf{v^b}_j > 0 |
| 112 | |
| 113 | In the end the dual potentials are centered using function |
| 114 | :py:func:`ot.lp.center_ot_dual`. |
| 115 | |
| 116 | Note that all those updates do not change the objective value of the |
| 117 | solution but provide dual potentials that do not violate the constraints. |
| 118 | |
| 119 | Parameters |
| 120 | ---------- |
| 121 | alpha0 : (ns,) numpy.ndarray, float64 |
| 122 | Source dual potential |
| 123 | beta0 : (nt,) numpy.ndarray, float64 |
| 124 | Target dual potential |
| 125 | alpha0 : (ns,) numpy.ndarray, float64 |
| 126 | Source dual potential |
| 127 | beta0 : (nt,) numpy.ndarray, float64 |
| 128 | Target dual potential |
| 129 | a : (ns,) numpy.ndarray, float64 |
| 130 | Source distribution (uniform weights if empty list) |
| 131 | b : (nt,) numpy.ndarray, float64 |
| 132 | Target distribution (uniform weights if empty list) |
| 133 | M : (ns,nt) numpy.ndarray, float64 |
| 134 | Loss matrix (c-order array with type float64) |
| 135 | |
| 136 | Returns |
| 137 | ------- |
no test coverage detected