Пример #1
0
// lifts a map from f:F -> Y over the map map: X -> Y. We only need relations
// for Y.
// Remark 1: does NOT catch if such a lift doesn't exist!
// Remark 2: If the map X -> Y is injective, then for a map A -> Y the lift F_A
// -> X of the map
//           F_A -> Y induces a well-defined map A -> X.
//           In general, the problem whether there IS such a lift, and how to
//           compute it,
//           will involve additional work.
MatrixQ lift_from_free(const mod_t p, const MatrixQ& f, const MatrixQ& map,
                       const AbelianGroup& Y)
{


  MatrixQ rel_y_map(map.height(), Y.tor_rank() + map.width());

  rel_y_map(Y.free_rank(), 0, Y.tor_rank(), Y.tor_rank()) = Y.torsion_matrix(p);

  rel_y_map(0, Y.tor_rank(), map.height(), map.width()) = map;

  MatrixQ proj(map.width(), Y.tor_rank() + map.width());
  proj(0, Y.tor_rank(), map.width(), map.width()) =
      MatrixQ::identity(map.width());

  MatrixQ f_copy(f);

  MatrixQRefList to_X_dummy;
  MatrixQRefList from_Y_dummy;
  MatrixQRefList from_X_ref;
  MatrixQRefList to_Y_ref;

  from_X_ref.emplace_back(proj);
  to_Y_ref.emplace_back(f_copy);

  smith_reduce_p(p, rel_y_map, to_X_dummy, from_X_ref, to_Y_ref, from_Y_dummy);

  MatrixQ lift(rel_y_map.width(), f.width());

  dim_t d_max = 0;
  while (d_max < rel_y_map.height() && d_max < rel_y_map.width() &&
         rel_y_map(d_max, d_max) != 0) {
    d_max++;
  }

  for (dim_t i = 0; i < d_max; i++) {
    for (dim_t j = 0; j < f.width(); j++) {
      lift(i, j) = f_copy(i, j) / rel_y_map(i, i);
    }
  }

  return proj * lift;
}