#include knot_diagram::knot_diagram (const planar_diagram &pd) : name(pd.name), n_crossings(pd.crossings.size ()), marked_edge(0), crossings(n_crossings), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { basedvector, 1>, 1> edge_ci (num_edges ()); for (unsigned c = 1; c <= n_crossings; c ++) { for (unsigned i = 1; i <= 4; i ++) { unsigned e = pd.crossings[c][i]; edge_ci[e].append (pair (c, i)); } crossings[c] = basedvector (4); } set done; for (unsigned c0 = 1; c0 <= n_crossings; c0 ++) { for (unsigned i0 = 1; i0 <= 2; i0 ++) { unsigned e = pd.crossings[c0][i0]; if (done % e) continue; for (unsigned c = c0, i = i0;;) { crossings[c][i] = edge_to_ept (e); done.push (e); ept_crossing[edge_to_ept (e)] = c; ept_index[edge_to_ept (e)] = i; i = add_base1_mod4 (i, 2); e = pd.crossings[c][i]; crossings[c][i] = edge_from_ept (e); ept_crossing[edge_from_ept (e)] = c; ept_index[edge_from_ept (e)] = i; if (edge_ci[e][1].first == c && edge_ci[e][1].second == i) { c = edge_ci[e][2].first; i = edge_ci[e][2].second; } else { assert (edge_ci[e][2].first == c && edge_ci[e][2].second == i); c = edge_ci[e][1].first; i = edge_ci[e][1].second; } if (c == c0 && i == i0) break; } } } assert (done.card () == num_edges ()); calculate_smoothing_orientation (); calculate_nminus_nplus (); } class dt_layout { public: knot_diagram &kd; unsigned n_components; basedvector comp_first_edge, comp_last_edge; basedvector edge_to_crossing; smallbitset edge_to_under; smallbitset placed; public: dt_layout (const dt_code &dt, knot_diagram &kd_); dt_layout (const dt_layout &) = delete; ~dt_layout () { } dt_layout &operator = (const dt_layout &) = delete; unsigned find_crossing (unsigned prevc, unsigned previ, unsigned target, bool under, unsigned dir); bool layout_2 (unsigned e, unsigned prevc, unsigned previ, unsigned c, unsigned i); bool layout_1 (unsigned e, unsigned prevc, unsigned previ); unsigned comp_next_edge (unsigned e) const; void layout (); }; dt_layout::dt_layout (const dt_code &dt, knot_diagram &kd_) : kd(kd_), n_components(dt.num_components ()), comp_first_edge(n_components), comp_last_edge(n_components), edge_to_crossing(kd.num_edges ()), edge_to_under(kd.num_edges ()), placed(kd.n_crossings) { unsigned k = 1; for (unsigned i = 1; i <= dt.even_labels.size (); i ++) { comp_first_edge[i] = 2 * k - 1; comp_last_edge[i] = 2 * (k + dt.even_labels[i].size () - 1); for (unsigned j = 1; j <= dt.even_labels[i].size (); j ++, k ++) { int as = dt.even_labels[i][j]; unsigned a = abs (as), b = 2 * k - 1; if (as > 0) edge_to_under.push (a); else edge_to_under.push (b); edge_to_crossing[a] = edge_to_crossing[b] = k; } } } unsigned dt_layout::find_crossing (unsigned prevc, unsigned previ, unsigned target, bool under, unsigned dir) { assert (!kd.crossings[prevc][previ]); assert (placed % prevc); unsigned c = prevc, i = add_base1_mod4 (previ, dir); for (;;) { if (c == prevc && i == previ) return 0; if (c == target && under == (i == 1 || i == 3) && kd.crossings[c][i] == 0) return i; unsigned p = kd.crossings[c][i]; if (p) { unsigned p2 = kd.edge_other_ept (p); c = kd.ept_crossing[p2]; i = kd.ept_index[p2]; } i = add_base1_mod4 (i, dir); } } unsigned dt_layout::comp_next_edge (unsigned e) const { for (unsigned comp = 1; comp <= n_components; comp ++) { if (comp_first_edge[comp] <= e && e <= comp_last_edge[comp]) { if (e == comp_last_edge[comp]) return comp_first_edge[comp]; else return e + 1; } } abort (); } bool dt_layout::layout_2 (unsigned e, unsigned prevc, unsigned previ, unsigned c, unsigned i) { assert (placed % prevc); assert (placed % c); unsigned from = kd.edge_from_ept (e), to = kd.edge_to_ept (e); assert (kd.crossings[prevc][previ] == 0); kd.crossings[prevc][previ] = from; kd.ept_crossing[from] = prevc; kd.ept_index[from] = previ; assert (kd.crossings[c][i] == 0); kd.crossings[c][i] = to; kd.ept_crossing[to] = c; kd.ept_index[to] = i; if (layout_1 (comp_next_edge (e), c, add_base1_mod4 (i, 2))) return 1; kd.crossings[prevc][previ] = 0; kd.crossings[c][i] = 0; kd.ept_crossing[from] = kd.ept_crossing[to] = 0; kd.ept_index[from] = kd.ept_index[to] = 0; return 0; } bool dt_layout::layout_1 (unsigned e, unsigned prevc, unsigned previ) { if (kd.crossings[prevc][previ]) { unsigned from = kd.edge_from_ept (e); assert (kd.crossings[prevc][previ] == from); assert (kd.ept_crossing[from] == prevc); assert (kd.ept_index[from] == previ); for (unsigned e = 1; e <= kd.num_edges (); e ++) { unsigned to = kd.edge_to_ept (e); unsigned prevc = edge_to_crossing[e]; if (placed % prevc && !kd.ept_crossing[to]) { unsigned previ1 = edge_to_under % e ? 3 : 4; if (layout_1 (comp_next_edge (e), prevc, previ1)) return 1; unsigned previ2 = edge_to_under % e ? 1 : 2; return layout_1 (comp_next_edge (e), prevc, previ2); } } /* done! */ return 1; } unsigned c = edge_to_crossing[e]; if (placed % c) { unsigned i = find_crossing (prevc, previ, c, edge_to_under % e, 1); if (i && layout_2 (e, prevc, previ, c, i)) return 1; unsigned i2 = find_crossing (prevc, previ, c, edge_to_under % e, 3); return i2 && layout_2 (e, prevc, previ, c, i2); // return i && ... ?? } else { unsigned i = (edge_to_under % e) ? 1 : 2; placed.push (c); if (!layout_2 (e, prevc, previ, c, i)) { placed -= c; return 0; } else return 1; } } void dt_layout::layout () { unsigned last = comp_last_edge[1]; unsigned prevc = edge_to_crossing[last]; unsigned previ = (edge_to_under % last) ? 3 : 4; placed.push (prevc); bool b = layout_1 (comp_first_edge[1], prevc, previ); assert (b); assert (placed.card () == kd.n_crossings); } knot_diagram::knot_diagram (const dt_code &dt) : name(dt.name), n_crossings(dt.num_crossings ()), marked_edge(0), crossings(n_crossings), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { for (unsigned i = 1; i <= n_crossings; i ++) { basedvector v (4); v[1] = v[2] = v[3] = v[4] = 0; crossings[i] = v; } dt_layout layout (dt, *this); layout.layout (); calculate_nminus_nplus (); calculate_smoothing_orientation (); } knot_diagram::knot_diagram (sublink, smallbitset c, const knot_diagram &kd) : name(kd.name), n_crossings(0), marked_edge(0), nminus(0), nplus(0) { // ??? assert (!kd.marked_edge); assert (c.card () > 0); // no empty diagrams // edge x component unionfind<1> u (kd.num_edges ()); for (unsigned i = 1; i <= kd.n_crossings; i ++) { u.join (kd.ept_edge (kd.crossings[i][1]), kd.ept_edge (kd.crossings[i][3])); u.join (kd.ept_edge (kd.crossings[i][2]), kd.ept_edge (kd.crossings[i][4])); } assert (u.num_sets () == c.size ()); ullmanset<1> u_sets (kd.num_edges ()); for (unsigned i = 1; i <= kd.num_edges (); i ++) u_sets += u.find (i); ullmanset<1> sub_crossings (kd.n_crossings), sub_edges (kd.num_edges ()); for (unsigned i = 1; i <= kd.num_edges (); i ++) { if (c % (u_sets.position (u.find (i)) + 1)) sub_edges.push (i); } // sub edge x sublink edge unionfind<1> subu (sub_edges.card ()); set active_comps; for (unsigned i = 1; i <= kd.n_crossings; i ++) { unsigned c1 = u_sets.position (u.find (kd.ept_edge (kd.crossings[i][1]))) + 1, c2 = u_sets.position (u.find (kd.ept_edge (kd.crossings[i][2]))) + 1; if (c % c1 && c % c2) { sub_crossings.push (i); active_comps += c1; active_comps += c2; } else { if (c % (u_sets.position (u.find (kd.ept_edge (kd.crossings[i][1]))) + 1)) { subu.join (sub_edges.position (kd.ept_edge (kd.crossings[i][1])) + 1, sub_edges.position (kd.ept_edge (kd.crossings[i][3])) + 1); } if (c % (u_sets.position (u.find (kd.ept_edge (kd.crossings[i][2]))) + 1)) { subu.join (sub_edges.position (kd.ept_edge (kd.crossings[i][2])) + 1, sub_edges.position (kd.ept_edge (kd.crossings[i][4])) + 1); } } } n_crossings = (sub_crossings.card () + (c.card () - active_comps.card ())); assert (n_crossings > 0); ullmanset<1> subu_sets (sub_edges.card ()); for (unsigned i = 1; i <= sub_edges.card (); i ++) subu_sets += subu.find (i); crossings = basedvector, 1> (n_crossings); for (unsigned i = 1; i <= n_crossings; i ++) crossings[i] = basedvector (4); for (ullmanset_const_iter<1> i = sub_crossings; i; i ++) { unsigned c = i.val (), new_c = i.pos () + 1; unsigned e1 = (subu_sets.position (subu.find (sub_edges.position (kd.ept_edge (kd.crossings[c][1])) + 1)) + 1), e2 = (subu_sets.position (subu.find (sub_edges.position (kd.ept_edge (kd.crossings[c][2])) + 1)) + 1), e3 = (subu_sets.position (subu.find (sub_edges.position (kd.ept_edge (kd.crossings[c][3])) + 1)) + 1), e4 = (subu_sets.position (subu.find (sub_edges.position (kd.ept_edge (kd.crossings[c][4])) + 1)) + 1); if (kd.is_from_ept (kd.crossings[c][1])) crossings[new_c][1] = edge_from_ept (e1); else crossings[new_c][1] = edge_to_ept (e1); if (kd.is_from_ept (kd.crossings[c][2])) crossings[new_c][2] = edge_from_ept (e2); else crossings[new_c][2] = edge_to_ept (e2); if (kd.is_from_ept (kd.crossings[c][3])) crossings[new_c][3] = edge_from_ept (e3); else crossings[new_c][3] = edge_to_ept (e3); if (kd.is_from_ept (kd.crossings[c][4])) crossings[new_c][4] = edge_from_ept (e4); else crossings[new_c][4] = edge_to_ept (e4); } unsigned e = subu.num_sets (); unsigned new_c = sub_crossings.card (); for (smallbitset_const_iter i = c; i; i ++) { if (active_comps % i.val ()) continue; unsigned e1 = (subu_sets.position (subu.find (sub_edges.position (u_sets.nth (i.val () - 1)) + 1)) + 1); unsigned e2 = ++ e; unsigned c = ++ new_c; crossings[c][1] = edge_from_ept (e1); crossings[c][2] = edge_to_ept (e1); crossings[c][3] = edge_to_ept (e2); crossings[c][4] = edge_from_ept (e2); } assert (e == num_edges ()); assert (new_c == n_crossings); // ?? break this out into aux function ept_crossing = basedvector (num_epts ()); ept_index = basedvector (num_epts ()); for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; ept_crossing[p] = i; ept_index[p] = j; } } #ifndef NDEBUG check_crossings (); #endif calculate_smoothing_orientation (); calculate_nminus_nplus (); } knot_diagram::knot_diagram (disjoint_union, const knot_diagram &kd1, const knot_diagram &kd2) : name(kd1.name + "+" + kd2.name), n_crossings(kd1.n_crossings + kd2.n_crossings), marked_edge(0), crossings(n_crossings), nminus(kd1.nminus + kd2.nminus), nplus(kd1.nplus + kd2.nplus) { assert (kd1.marked_edge == 0); assert (kd2.marked_edge == 0); for (unsigned i = 1; i <= n_crossings; i ++) crossings[i] = basedvector (4); for (unsigned i = 1; i <= kd1.n_crossings; i ++) for (unsigned j = 1; j <= 4; j ++) crossings[i][j] = kd1.crossings[i][j]; for (unsigned e = 1; e <= kd1.num_edges (); e ++) { if (kd1.edge_smoothing_oriented % e) edge_smoothing_oriented.push (e); } for (unsigned i = 1; i <= kd2.n_crossings; i ++) for (unsigned j = 1; j <= 4; j ++) crossings[kd1.n_crossings + i][j] = kd1.num_epts () + kd2.crossings[i][j]; for (unsigned e = 1; e <= kd2.num_edges (); e ++) { if (kd2.edge_smoothing_oriented % e) edge_smoothing_oriented.push (kd1.num_edges () + e); } // ?? break this out into aux function ept_crossing = basedvector (num_epts ()); ept_index = basedvector (num_epts ()); for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; ept_crossing[p] = i; ept_index[p] = j; } } #ifndef NDEBUG check_crossings (); #endif } knot_diagram::knot_diagram (mirror, const knot_diagram &kd) : name("mirror(" + kd.name + ")"), n_crossings(kd.n_crossings), marked_edge(0), crossings(n_crossings), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { for (unsigned i = 1; i <= n_crossings; i ++) { basedvector v (4); v[1] = kd.crossings[i][1]; v[2] = kd.crossings[i][4]; v[3] = kd.crossings[i][3]; v[4] = kd.crossings[i][2]; crossings[i] = v; } for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned c = crossings[i][j]; ept_crossing[c] = i; ept_index[c] = j; } } calculate_smoothing_orientation (); calculate_nminus_nplus (); assert (nminus == kd.nplus); assert (nplus == kd.nminus); } void knot_diagram::check_crossings () { for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; assert (ept_crossing[p] == i); assert (ept_index[p] == j); } } for (unsigned i = 1; i <= num_edges (); i ++) { unsigned to = edge_to_ept (i); assert (is_from_ept (crossings[ept_crossing[to]][add_base1_mod4 (ept_index[to], 2)])); } } void knot_diagram::rotate_crossing (unsigned c) { std::swap (crossings[c][1], crossings[c][3]); std::swap (crossings[c][2], crossings[c][4]); for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[c][j]; ept_index[p] = j; } } unsigned knot_diagram::total_linking_number () const { unionfind<1> u (num_edges ()); for (unsigned i = 1; i <= n_crossings; i ++) { u.join (ept_edge (crossings[i][1]), ept_edge (crossings[i][3])); u.join (ept_edge (crossings[i][2]), ept_edge (crossings[i][4])); } unsigned n = u.num_sets (); map root_comp; unsigned t = 0; for (unsigned i = 1; i <= num_edges (); i ++) { if (u.find (i) == i) { ++ t; root_comp.push (i, t); } } assert (t == n); unsigned total_lk = 0; for (unsigned i = 1; i <= n; i ++) for (unsigned j = i + 1; j <= n; j ++) { if (i == j) continue; int lk = 0; for (unsigned x = 1; x <= n_crossings; x ++) { unsigned r1 = root_comp(u.find (ept_edge (crossings[x][1]))), r2 = root_comp(u.find (ept_edge (crossings[x][2]))); if (((r1 == i) && (r2 == j)) || ((r2 == i) && (r1 == j))) { if (is_to_ept (crossings[x][1]) == is_to_ept (crossings[x][4])) lk ++; else lk --; } } assert (is_even (lk)); lk /= 2; total_lk += abs (lk); } return total_lk; } knot_diagram::knot_diagram (connect_sum, const knot_diagram &d1, const knot_diagram &d2) : name(d1.name + "\\#" + d2.name), n_crossings(d1.n_crossings + d2.n_crossings), marked_edge(0), crossings(n_crossings), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { for (unsigned i = 1; i <= d1.n_crossings; i ++) crossings[i] = basedvector (COPY, d1.crossings[i]); for (unsigned i = 1; i <= d2.n_crossings; i ++) { basedvector v (4); for (unsigned j = 1; j <= 4; j ++) v[j] = d1.num_epts () + d2.crossings[i][j]; crossings[d1.n_crossings + i] = v; } unsigned p1 = d1.edge_from_ept (1); crossings[d1.ept_crossing[p1]][d1.ept_index[p1]] = edge_from_ept (d1.num_edges () + 1); unsigned p2 = d2.edge_from_ept (1); crossings[d1.n_crossings + d2.ept_crossing[p2]][d2.ept_index[p2]] = d1.edge_from_ept (1); for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; ept_crossing[p] = i; ept_index[p] = j; } } #ifndef NDEBUG check_crossings (); #endif orient (); calculate_smoothing_orientation (); calculate_nminus_nplus (); } knot_diagram::knot_diagram (const std::string &name_, unsigned n_crossings_, unsigned crossings_ar[][4]) : name(name_), n_crossings(n_crossings_), marked_edge(0), crossings(n_crossings), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { for (unsigned i = 1; i <= n_crossings; i ++) { basedvector v (4); v[1] = crossings_ar[i - 1][0]; v[2] = crossings_ar[i - 1][1]; v[3] = crossings_ar[i - 1][2]; v[4] = crossings_ar[i - 1][3]; crossings[i] = v; for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; ept_crossing[p] = i; ept_index[p] = j; } } calculate_smoothing_orientation (); calculate_nminus_nplus (); } knot_diagram::knot_diagram (const std::string &name_, const basedvector, 1> &crossings_) : name(name_), n_crossings(crossings_.size ()), marked_edge(0), crossings(crossings_), ept_crossing(num_epts ()), ept_index(num_epts ()), nminus(0), nplus(0) { for (unsigned i = 1; i <= n_crossings; i ++) { for (unsigned j = 1; j <= 4; j ++) { unsigned p = crossings[i][j]; ept_crossing[p] = i; ept_index[p] = j; } } calculate_smoothing_orientation (); calculate_nminus_nplus (); } void knot_diagram::orient () { bitset done (num_edges ()); for (unsigned i = 1; i <= num_edges (); i ++) { if (done % i) continue; unsigned p = edge_to_ept (i); for (;;) { unsigned e = ept_edge (p); done.push (e); if (is_from_ept (p)) { unsigned e_from = edge_from_ept (e), e_to = edge_to_ept (e), c_from = ept_crossing[e_from], c_to = ept_crossing[e_to], j_from = ept_index[e_from], j_to = ept_index[e_to]; ept_crossing[e_to] = c_from; ept_index[e_to] = j_from; ept_crossing[e_from] = c_to; ept_index[e_from] = j_to; crossings[c_from][j_from] = e_to; crossings[c_to][j_to] = e_from; p = e_to; } p = crossings[ept_crossing[p]][add_base1_mod4 (ept_index[p], 2)]; if (ept_edge (p) == i) break; p = edge_other_ept (p); } } assert (done.card () == num_edges ()); #ifndef NDEBUG check_crossings (); #endif } void knot_diagram::calculate_nminus_nplus () { assert (nplus == 0 && nminus == 0); for (unsigned i = 1; i <= n_crossings; i ++) { if (is_to_ept (crossings[i][1]) == is_to_ept (crossings[i][4])) nplus ++; else nminus ++; } } void knot_diagram::calculate_smoothing_orientation () { edge_smoothing_oriented = set (); set done; vector q; for (unsigned i = 1; i <= num_edges (); i ++) { if (done % i) continue; edge_smoothing_oriented.push (i); done.push (i); q.append (i); while (q.size () != 0) { unsigned e = q.pop (); assert (done % e); unsigned p = edge_smoothing_to_ept (e); unsigned r = resolve_next_ept (p, 0); unsigned f = ept_edge (r); if (done % f) assert (is_smoothing_from_ept (r)); else { if (is_from_ept (r)) edge_smoothing_oriented.push (f); done.push (f); q.append (f); } unsigned r2 = resolve_next_ept (p, 1); unsigned f2 = ept_edge (r2); if (done % f2) assert (is_smoothing_from_ept (r2)); else { if (is_from_ept (r2)) edge_smoothing_oriented.push (f2); done.push (f2); q.append (f2); } } } assert (done.card () == num_edges ()); } unsigned knot_diagram::resolve_next_ept (unsigned p, bool resolution) const { static unsigned lookup[2][4] = { { 2, 1, 4, 3 }, { 4, 3, 2, 1 } }; unsigned c = ept_crossing[p], i = ept_index[p]; assert (i >= 1 && i <= 4); i = lookup[(int)resolution][i - 1]; return crossings[c][i]; } static unsigned crossing_index_corner (unsigned c, unsigned i) { return (c - 1) * 4 + i; } static unsigned corner_crossing (unsigned x) { return (x - 1) / 4 + 1; } static unsigned corner_index (unsigned x) { return ((x - 1) % 4) + 1; } unsigned knot_diagram::num_components () const { unionfind<1> u (num_edges ()); for (unsigned i = 1; i <= n_crossings; i ++) { u.join (ept_edge (crossings[i][1]), ept_edge (crossings[i][3])); u.join (ept_edge (crossings[i][2]), ept_edge (crossings[i][4])); } return u.num_sets (); } directed_multigraph knot_diagram::black_graph (basedvector &bg_edge_height) const { unsigned n_corners = n_crossings * 4; #if 1 for (unsigned c = 1; c <= n_crossings; c ++) for (unsigned j = 1; j <= 4; j ++) { unsigned x = crossing_index_corner (c, j); assert (x >= 1 && x <= n_corners); assert (corner_crossing (x) == c); assert (corner_index (x) == j); } for (unsigned x = 1; x <= n_corners; x ++) { unsigned c = corner_crossing (x); assert (c >= 1 && c <= n_crossings); unsigned j = corner_index (x); assert (j >= 1 && j <= 4); assert (crossing_index_corner (c, j) == x); } #endif unionfind<1> u (n_corners); unsigned n_edges = num_edges (); for (unsigned i = 1; i <= n_edges; i ++) { unsigned i_from = edge_from_ept (i), i_to = edge_to_ept (i); u.join (crossing_index_corner (ept_crossing (i_from), ept_index (i_from)), crossing_index_corner (ept_crossing (i_to), add_base1_mod4 (ept_index (i_to), 3))); u.join (crossing_index_corner (ept_crossing (i_from), add_base1_mod4 (ept_index (i_from), 3)), crossing_index_corner (ept_crossing (i_to), ept_index (i_to))); } ullmanset<1> present (n_corners); for (unsigned i = 1; i <= n_corners; i ++) present += u.find (i); basedvector edge_from, edge_to; basedvector edge_height; for (unsigned i = 1; i <= n_crossings; i ++) { edge_from.append (present.position (u.find (crossing_index_corner (i, 1))) + 1); edge_to.append (present.position (u.find (crossing_index_corner (i, 3))) + 1); edge_height.append (1); edge_from.append (present.position (u.find (crossing_index_corner (i, 2))) + 1); edge_to.append (present.position (u.find (crossing_index_corner (i, 4))) + 1); edge_height.append (0); } assert (u.num_sets () == present.card ()); directed_multigraph bwg (u.num_sets (), edge_from, edge_to); // display ("bwg:\n", bwg); assert (bwg.num_components () == 2); basedvector edge_inj, vertex_inj; directed_multigraph bg = bwg.component (1, edge_inj, vertex_inj); bg_edge_height = basedvector (bg.num_edges ()); for (unsigned i = 1; i <= bg.num_edges (); i ++) bg_edge_height[i] = edge_height[edge_inj[i]]; return bg; } basedvector, 1> knot_diagram::planar_diagram_crossings () const { unsigned n_edges = num_edges (); ullmanset<1> edges (n_edges); for (unsigned e = 1; e <= n_edges; e ++) { if (edges % e) continue; for (unsigned i = e;;) { edges.push (i); unsigned c = ept_crossing[edge_to_ept (i)], j = ept_index[edge_to_ept (i)]; unsigned j2 = add_base1_mod4 (j, 2); assert (is_from_ept (crossings[c][j2])); i = ept_edge (crossings[c][j2]); if (i == e) break; } } assert (edges.card () == n_edges); basedvector, 1> r (n_crossings); unsigned k = 0; bool first = 1; for (unsigned i = 1; i <= n_edges; i ++) { unsigned e = edges.nth (i - 1); unsigned c = ept_crossing[edge_to_ept (e)], j = ept_index[edge_to_ept (e)]; if (j == 1) { basedvector v (4); v[1] = edges.position (ept_edge (crossings[c][1])) + 1; v[2] = edges.position (ept_edge (crossings[c][2])) + 1; v[3] = edges.position (ept_edge (crossings[c][3])) + 1; v[4] = edges.position (ept_edge (crossings[c][4])) + 1; r[++ k] = v; } else if (j == 3) { basedvector v (4); v[1] = edges.position (ept_edge (crossings[c][3])) + 1; v[2] = edges.position (ept_edge (crossings[c][4])) + 1; v[3] = edges.position (ept_edge (crossings[c][1])) + 1; v[4] = edges.position (ept_edge (crossings[c][2])) + 1; r[++ k] = v; } unsigned j2 = add_base1_mod4 (j, 2); assert (is_from_ept (crossings[c][j2])); unsigned e2 = ept_edge (crossings[c][j2]); unsigned i2 = edges.position (e2) + 1; #if 0 assert ((i == n_edges && i2 == 1) || i2 == i + 1); #endif } assert (k == n_crossings); return r; } basedvector, 1> knot_diagram::as_gauss_code () const { set visited; unsigned m = num_components (); basedvector, 1> gc (m); unsigned k = 0; // index component for (unsigned i = 1; i <= num_edges (); i ++) { if (visited % i) continue; basedvector comp_gc; unsigned p = edge_to_ept (i); for (unsigned j = i;;) { visited.push (j); unsigned c = ept_crossing[p]; int t = (is_over_ept (p) ? -c : c); comp_gc.append (t); p = crossings[c][add_base1_mod4 (ept_index[p], 2)]; p = edge_other_ept (p); assert (is_to_ept (p)); j = ept_edge (p); if (j == i) break; } ++ k; gc[k] = comp_gc; } assert (visited.card () == num_edges ()); #ifndef NDEBUG unsigned n = 0; for (unsigned i = 1; i <= m; i ++) n += gc[i].size (); assert (n == 2*n_crossings); #endif return gc; } hash_t knot_diagram::hash_self () const { // ??? we can do better unsigned n_loops = 0; for (unsigned i = 1; i <= num_edges (); i ++) { if (ept_edge (edge_from_ept (i)) == ept_edge (edge_to_ept (i))) n_loops ++; } return hash_combine (hash (n_crossings), hash (n_loops)); } void knot_diagram::show_ept (unsigned p) const { unsigned e = ept_edge (p); if (is_to_ept (p)) printf (">"); printf ("%d", e); if (is_from_ept (p)) printf (">"); } void knot_diagram::show_self () const { printf ("knot_diagram %s", name.c_str ()); } void knot_diagram::display_self () const { comment (); printf ("knot_diagram %s\n", name.c_str ()); comment (); printf ("n_crossings = %d, n+ = %d, n- = %d\n", n_crossings, nplus, nminus); if (marked_edge) { comment (); printf ("marked_edge = %d\n", marked_edge); } comment (); for (unsigned i = 1; i <= crossings.size (); i ++) { printf ("%d:(", i); show_ept (crossings[i][1]); printf (" "); show_ept (crossings[i][2]); printf (" "); show_ept (crossings[i][3]); printf (" "); show_ept (crossings[i][4]); printf (")"); } printf ("\n"); }