|
| 1 | +# ̃xᵀ̃Hx̃ + ̃ĉᵀx̃ + lⱼ²Hⱼⱼ + cⱼxⱼ + c₀ |
| 2 | +# ̂c = ̃c + 2lⱼΣₖHⱼₖxₖ , k ≂̸ j |
| 3 | + |
| 4 | +""" |
| 5 | + xrm, c0ps, nvarrm = remove_ifix!(ifix, Hrows, Hcols, Hvals, nvar, |
| 6 | + Arows, Acols, Avals, c, c0, |
| 7 | + lvar, uvar, lcon, ucon) |
| 8 | +
|
| 9 | +Remove rows and columns in H, columns in A, and elements in lcon and ucon |
| 10 | +corresponding to fixed variables, that are in `ifix` |
| 11 | +(They should be the indices `i` where `lvar[i] == uvar[i]`). |
| 12 | +
|
| 13 | +Returns the removed elements of `lvar` (or `uvar`), the constant term in the QP |
| 14 | +objective `c0ps` resulting from the fixed variables, and the new number of variables `nvarrm`. |
| 15 | +`Hrows`, `Hcols`, `Hvals`, `Arows`, `Acols`, `Avals`, `c`, `lvar`, `uvar`, |
| 16 | +`lcon` and `ucon` are updated in-place. |
| 17 | +""" |
| 18 | +function remove_ifix!( |
| 19 | + ifix, |
| 20 | + Hrows, |
| 21 | + Hcols, |
| 22 | + Hvals, |
| 23 | + nvar, |
| 24 | + Arows, |
| 25 | + Acols, |
| 26 | + Avals, |
| 27 | + c::AbstractVector{T}, |
| 28 | + c0, |
| 29 | + lvar, |
| 30 | + uvar, |
| 31 | + lcon, |
| 32 | + ucon, |
| 33 | +) where {T} |
| 34 | + |
| 35 | + # assume Hcols is sorted |
| 36 | + c0_offset = zero(T) |
| 37 | + Hnnz = length(Hrows) |
| 38 | + Hrm = 0 |
| 39 | + Annz = length(Arows) |
| 40 | + Arm = 0 |
| 41 | + # assume ifix is sorted and length(ifix) > 0 |
| 42 | + nfix = length(ifix) |
| 43 | + |
| 44 | + # remove ifix 1 by 1 in H and A and update QP data |
| 45 | + for idxfix = 1:nfix |
| 46 | + currentifix = ifix[idxfix] |
| 47 | + xifix = lvar[currentifix] |
| 48 | + # index of the current fixed variable that takes the number of |
| 49 | + # already removed variables into account: |
| 50 | + newcurrentifix = currentifix - idxfix + 1 |
| 51 | + |
| 52 | + Hwritepos = 1 |
| 53 | + # shift corresponding to the already removed fixed variables to update c: |
| 54 | + shiftHj = 1 |
| 55 | + if Hnnz > 0 |
| 56 | + oldHj = Hrows[1] |
| 57 | + end |
| 58 | + # remove ifix in H and update data |
| 59 | + k = 1 |
| 60 | + while k <= Hnnz && Hcols[k] <= (nvar - idxfix + 1) |
| 61 | + Hi, Hj, Hx = Hrows[k], Hcols[k], Hvals[k] # Hj sorted |
| 62 | + |
| 63 | + while (Hj == oldHj) && shiftHj <= idxfix - 1 && Hj + shiftHj - 1 >= ifix[shiftHj] |
| 64 | + shiftHj += 1 |
| 65 | + end |
| 66 | + shiftHi = 1 |
| 67 | + while shiftHi <= idxfix - 1 && Hi + shiftHi - 1 >= ifix[shiftHi] |
| 68 | + shiftHi += 1 |
| 69 | + end |
| 70 | + if Hi == Hj == newcurrentifix |
| 71 | + Hrm += 1 |
| 72 | + c0_offset += xifix^2 * Hx / 2 |
| 73 | + elseif Hi == newcurrentifix |
| 74 | + Hrm += 1 |
| 75 | + c[Hj + shiftHj - 1] += xifix * Hx |
| 76 | + elseif Hj == newcurrentifix |
| 77 | + Hrm += 1 |
| 78 | + c[Hi + shiftHi - 1] += xifix * Hx |
| 79 | + else # keep Hi, Hj, Hx |
| 80 | + Hrows[Hwritepos] = (Hi < newcurrentifix) ? Hi : Hi - 1 |
| 81 | + Hcols[Hwritepos] = (Hj < newcurrentifix) ? Hj : Hj - 1 |
| 82 | + Hvals[Hwritepos] = Hx |
| 83 | + Hwritepos += 1 |
| 84 | + end |
| 85 | + k += 1 |
| 86 | + end |
| 87 | + |
| 88 | + # remove ifix in A cols |
| 89 | + Awritepos = 1 |
| 90 | + currentAn = nvar - idxfix + 1 # remove rows if uplo == :U |
| 91 | + k = 1 |
| 92 | + while k <= Annz && Acols[k] <= currentAn |
| 93 | + Ai, Aj, Ax = Arows[k], Acols[k], Avals[k] |
| 94 | + if Aj == newcurrentifix |
| 95 | + Arm += 1 |
| 96 | + lcon[Ai] -= Ax * xifix |
| 97 | + ucon[Ai] -= Ax * xifix |
| 98 | + else |
| 99 | + if Awritepos != k |
| 100 | + Arows[Awritepos] = Ai |
| 101 | + Acols[Awritepos] = (Aj < newcurrentifix) ? Aj : Aj - 1 |
| 102 | + Avals[Awritepos] = Ax |
| 103 | + end |
| 104 | + Awritepos += 1 |
| 105 | + end |
| 106 | + k += 1 |
| 107 | + end |
| 108 | + |
| 109 | + # update c0 with c[currentifix] coeff |
| 110 | + c0_offset += c[currentifix] * xifix |
| 111 | + end |
| 112 | + |
| 113 | + # resize Q and A |
| 114 | + if nfix > 0 |
| 115 | + Hnnz -= Hrm |
| 116 | + Annz -= Arm |
| 117 | + resize!(Hrows, Hnnz) |
| 118 | + resize!(Hcols, Hnnz) |
| 119 | + resize!(Hvals, Hnnz) |
| 120 | + resize!(Arows, Annz) |
| 121 | + resize!(Acols, Annz) |
| 122 | + resize!(Avals, Annz) |
| 123 | + end |
| 124 | + |
| 125 | + # store removed x values |
| 126 | + xrm = lvar[ifix] |
| 127 | + |
| 128 | + # remove coefs in lvar, uvar, c |
| 129 | + deleteat!(c, ifix) |
| 130 | + deleteat!(lvar, ifix) |
| 131 | + deleteat!(uvar, ifix) |
| 132 | + |
| 133 | + # update c0 |
| 134 | + c0ps = c0 + c0_offset |
| 135 | + |
| 136 | + nvarrm = nvar - nfix |
| 137 | + |
| 138 | + return xrm, c0ps, nvarrm |
| 139 | +end |
| 140 | + |
| 141 | +function restore_ifix!(ifix, xrm, x, xout) |
| 142 | + # put x and xrm inside xout |
| 143 | + cfix, cx = 1, 1 |
| 144 | + nfix = length(ifix) |
| 145 | + for i = 1:length(xout) |
| 146 | + if cfix <= nfix && i == ifix[cfix] |
| 147 | + xout[i] = xrm[cfix] |
| 148 | + cfix += 1 |
| 149 | + else |
| 150 | + xout[i] = x[cx] |
| 151 | + cx += 1 |
| 152 | + end |
| 153 | + end |
| 154 | +end |
0 commit comments