33 using T = linalg::matrix_scalar_t<CoordMapT>;
36 static constexpr std::size_t
N = linalg::space_dim_v<DecVarDom>;
46 const CB& cb_in,
const EqMap& eq_in,
47 const CanonicalTrace& trace_in = {})
64 template <std::size_t SharedCols, affine::AffineMapLike LiftedMap,
66 constexpr auto make(
int idx,
const LiftedMap& lift_map,
67 const std::tuple<Cs...>& cones)
const {
68 const auto new_map = this->
template update_map<SharedCols>();
69 const auto new_eq_map = this->
template update_eq_map<SharedCols>();
70 static constexpr std::size_t FullDom =
71 linalg::mat_cols_v<
decltype(new_map.linear_part())>;
72 constexpr std::size_t FreshCols =
73 linalg::mat_cols_v<CoordMapT> - SharedCols;
74 static_assert(FreshCols > 0,
"Lifted emission must append an auxiliary");
76 linalg::Vector<T, FullDom> sel{};
77 linalg::Vector<T, 1> bias{lift_map.translation()(0)};
79 AK_ASSERT(idx < 0 &&
static_cast<std::size_t
>(-idx) <= FreshCols &&
80 "Aux variable selector must select a fresh column in "
81 "CanonicalFormBuilder::make");
83 const std::size_t selector_idx = FullDom -
static_cast<std::size_t
>(-idx);
84 sel(selector_idx) = lift_map.linear_part()(0, 0);
85 const linalg::RowVector<T, FullDom> sel_row = linalg::as_row_vector(sel);
86 const auto new_coord_map =
87 affine::AffineMap<decltype(sel_row)>(sel_row, bias);
90 return make_builder<DecVarDom>(new_coord_map, new_cb, new_eq_map,
101 template <std::size_t SharedCols,
typename... Cs>
102 constexpr auto make(
const std::tuple<Cs...>& cones)
const {
103 const auto new_map = this->
template update_map<SharedCols>();
104 const auto new_eq_map = this->
template update_eq_map<SharedCols>();
107 return make_builder<DecVarDom>(new_map, new_cb, new_eq_map,
124 constexpr auto realize(
int idx,
const LiftedMap& lift_map,
125 const Emission& emission)
const {
128 constexpr std::size_t ChildCols = linalg::mat_cols_v<CoordMapT>;
129 const auto traced = add_cone_trace<Type, Emission>(emission);
130 const auto local_builder = make_builder<DecVarDom>(
131 emission.local_coord_map,
cb, emission.local_eq_map, traced);
132 return local_builder.template make<ChildCols>(idx, lift_map,
133 emission.local_cones);
144 template <convex::AtomType Type, LocalEmissionLike Emission>
145 constexpr auto realize(
const Emission& emission)
const {
146 const auto traced = add_cone_trace<Type, Emission>(emission);
147 const auto local_builder = make_builder<DecVarDom>(
148 emission.local_coord_map,
cb, emission.local_eq_map, traced);
149 constexpr std::size_t SharedCols =
150 std::max(
N, linalg::mat_cols_v<CoordMapT>);
151 return local_builder.template make<SharedCols>(emission.local_cones);
165 template <LocalEqualityEmissionLike Emission>
166 constexpr auto realize(
const Emission& emission)
const {
167 using CurrentEqMat = affine::affine_mat_t<EqMap>;
169 using LocalEqMat = affine::affine_mat_t<LocalEqMap>;
171 static_assert(std::same_as<T, linalg::matrix_scalar_t<LocalEqMat>>,
172 "type mismatch between equality emission and builder");
174 static constexpr std::size_t CurrentRows = linalg::mat_rows_v<CurrentEqMat>;
175 static constexpr std::size_t CurrentCols = linalg::mat_cols_v<CurrentEqMat>;
176 static constexpr std::size_t LocalRows = linalg::mat_rows_v<LocalEqMat>;
177 static constexpr std::size_t LocalCols = linalg::mat_cols_v<LocalEqMat>;
178 static constexpr std::size_t FullRows = CurrentRows + LocalRows;
179 static constexpr std::size_t FullCols =
180 std::max({
N, CurrentCols, LocalCols, cone_block_map_cols_v<CB>,
181 linalg::mat_cols_v<CoordMapT>});
183 linalg::Matrix<T, FullRows, FullCols> A{};
184 linalg::Vector<T, FullRows> b{};
186 if constexpr (CurrentRows != 0 && CurrentCols != 0) {
187 A = linalg::set_block<0, CurrentRows, 0, CurrentCols>(
189 for (std::size_t i = 0; i < CurrentRows; ++i)
190 b(i) =
eq_map.translation()(i);
193 if constexpr (LocalRows != 0 && LocalCols != 0) {
194 A = linalg::set_block<CurrentRows, FullRows, 0, LocalCols>(
195 A, emission.local_eq_map.linear_part());
196 for (std::size_t i = 0; i < LocalRows; ++i)
197 b(i + CurrentRows) = emission.local_eq_map.translation()(i);
200 const auto new_eq_map = affine::AffineMap<decltype(A)>(A, b);
201 const auto traced = add_equality_trace(emission);
202 return make_builder<DecVarDom>(
coord_map,
cb, new_eq_map, traced);
221 template <convex::AtomType Type, LocalEmissionLike Emission>
222 constexpr auto add_cone_trace(
const Emission& )
const {
224 using EqMapT = affine::affine_mat_t<EqMap>;
229 constexpr std::size_t NodeId =
231 constexpr std::size_t GlobalConeStart = conic::cone_block_num_cones_v<CB>;
232 constexpr std::size_t ConeOffsetStart = conic::cone_block_map_rows_v<CB>;
233 constexpr std::size_t LocalEqRows = emission_local_eq_rows_v<Emission>;
234 constexpr std::size_t EqOffsetStart = linalg::mat_rows_v<EqMapT>;
239 NodeId, GlobalConeStart, ConeOffsetStart);
241 if constexpr (LocalEqRows == 0) {
246 NodeId, 0, EqOffsetStart, LocalEqRows});
259 template <LocalEqualityEmissionLike Emission>
260 constexpr auto add_equality_trace(
const Emission& )
const {
261 using EqMapT = affine::affine_mat_t<EqMap>;
263 constexpr std::size_t NodeId =
265 constexpr std::size_t LocalEqRows = emission_local_eq_rows_v<Emission>;
266 constexpr std::size_t EqOffsetStart = linalg::mat_rows_v<EqMapT>;
271 if constexpr (LocalEqRows == 0) {
276 NodeId, 0, EqOffsetStart, LocalEqRows});
278 std::make_tuple(), equalities);
300 template <std::
size_t SharedCols>
301 struct ColumnLayout {
302 static constexpr std::size_t CoordCols = linalg::mat_cols_v<CoordMapT>;
305 constexpr ColumnLayout()
306 : prefix_cols(SharedCols),
308 std::max({SharedCols, cone_block_map_cols_v<CB>,
309 linalg::mat_cols_v<affine::affine_mat_t<EqMap>>})),
310 full_cols(auxiliary_start + CoordCols - SharedCols) {
311 static_assert(SharedCols >=
N && CoordCols >= SharedCols,
312 "Emission must preserve the decision/shared prefix");
319 const std::size_t full_cols;
332 template <std::
size_t SharedCols>
333 constexpr auto update_map()
const {
334 const auto& cone_map =
cb.map;
335 using ConeMapT = affine::affine_mat_t<
decltype(cone_map)>;
337 static_assert(std::same_as<T, linalg::matrix_scalar_t<ConeMapT>>,
338 "type mismatch between cone map and coord map");
340 static constexpr std::size_t CoordDom = linalg::mat_cols_v<CoordMapT>;
341 static constexpr std::size_t CoordCodom = linalg::mat_rows_v<CoordMapT>;
343 static constexpr std::size_t ConeDom = linalg::mat_cols_v<ConeMapT>;
344 static constexpr std::size_t ConeCodom = linalg::mat_rows_v<ConeMapT>;
345 constexpr ColumnLayout<SharedCols> layout{};
346 constexpr std::size_t PrefixCols = layout.prefix_cols;
347 constexpr std::size_t CoordAux = CoordDom - PrefixCols;
348 constexpr std::size_t FullDom = layout.full_cols;
349 constexpr std::size_t FullCodom = ConeCodom + CoordCodom;
350 constexpr std::size_t CoordAuxStartCol = layout.auxiliary_start;
351 constexpr std::size_t CoordAuxEndCol = CoordAuxStartCol + CoordAux;
353 linalg::Matrix<T, FullCodom, FullDom> F{};
354 linalg::Vector<T, FullCodom> g{};
357 if constexpr (ConeDom != 0) {
358 F = linalg::set_block<0, ConeCodom, 0, ConeDom>(F,
359 cone_map.linear_part());
360 for (std::size_t i = 0; i < ConeCodom; ++i)
361 g(i) = cone_map.translation()(i);
366 const auto dec_spanning_blk =
367 linalg::get_block<0, CoordCodom, 0, PrefixCols>(A);
368 F = linalg::set_block<ConeCodom, FullCodom, 0, PrefixCols>(
369 F, dec_spanning_blk);
372 if constexpr (CoordAux > 0) {
373 static_assert(CoordAuxEndCol > CoordAuxStartCol);
374 const auto coord_aux_blk =
375 linalg::get_block<0, CoordCodom, PrefixCols, CoordDom>(A);
376 F = linalg::set_block<ConeCodom, FullCodom, CoordAuxStartCol,
377 CoordAuxEndCol>(F, coord_aux_blk);
380 for (std::size_t i = 0; i < CoordCodom; ++i)
381 g(i + ConeCodom) =
coord_map.translation()(i);
383 return affine::AffineMap<decltype(F)>(F, g);
394 template <std::
size_t SharedCols>
395 constexpr auto update_eq_map()
const {
396 using EqMapT = affine::affine_mat_t<EqMap>;
398 static_assert(std::same_as<T, linalg::matrix_scalar_t<EqMapT>>,
399 "type mismatch between equality map and coord map");
401 static constexpr std::size_t EqDom = linalg::mat_cols_v<EqMapT>;
402 static constexpr std::size_t EqCodom = linalg::mat_rows_v<EqMapT>;
403 constexpr ColumnLayout<SharedCols> layout{};
404 constexpr std::size_t FullDom = layout.full_cols;
406 linalg::Matrix<T, EqCodom, FullDom> A{};
407 linalg::Vector<T, EqCodom> b{};
409 if constexpr (EqCodom != 0 && EqDom != 0) {
410 A = linalg::set_block<0, EqCodom, 0, EqDom>(A,
eq_map.linear_part());
411 for (std::size_t i = 0; i < EqCodom; ++i) b(i) =
eq_map.translation()(i);
416 return affine::AffineMap<decltype(A)>(A, b);