Mackey  V3.3
A C++ library for computing RO(G) graded homology
Tutorial

The code examples here can be compiled from the .cpp file in the demo folder.

Includes

Many parts of the library can be individually included. To keep things simple, we provide a single header file Mackey.hpp that includes the entire library (and Eigen)

Attention
If you are using MSVC, including Eigen will give compilation errors unless you define the following macro:
#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
Make sure to define the macro before including Mackey.hpp
Note
To enable multithreading via openMP define the macro MACKEY_USE_OPENMP before including Mackey.hpp and enable openMP in your compiler (on Clang and GCC this is done by the flag -fopenmp)

With that in mind, we start with:

  #include "Mackey.hpp"

Namespaces

Everything in this library is under the namespace mackey. For the following code examples we use:

  using namespace mackey;

Template parameters

The three template parameters that need to be set are the ambient group \(G\), the coefficient ring \(R\) and the \(G\)-space \(X\). For these examples let us use \(X=*\) which supports all of the library's features.

From the get-go the library provides support for:

  • groups \(G=C_{2^n}\) via the class C2Power
  • fields \(\mathbf Z/p\) via the class Z_mod
Note
The ring \(\mathbf Z\) corresponds to the usual signed integer types eg int64_t so there's no need to define a wrapper around it (64bit accuracy is more than enough for these computations, and you can use an overflow sanitizer to protect against it).

For example C2Power<5,Z_mod<3>> is the type corresponding to group \(C_{2^5}\) and coefficients \(\mathbf Z/3\).
Another example: C2Power<1,int64_t> corresponds to group \(C_2\) and coefficients \(\mathbf Z\) with 64bit range.

Note
We provide convenient typedefs for \(C_2,C_4,C_8,C_{16}\) via the classes C2, C4, C8, C16.
We provide a convenient typedef for \(\mathbf Z/2\) via Z2.

For the following examples we shall use the configuration:

  typedef C4<int64_t> group_t;

which means \(\mathbf Z\) coefficients and group \(C_4\).

Code Examples

The additive structure

The class AdditiveStructure computes the homology of all spheres in a given range as Mackey functors.

Example:

  AdditiveStructure<group_t> A({-3,-4},{5,6});

computes the homology of all spheres \(S^{n\sigma+m\lambda}\) with \(-3\leq n\leq 5, -4\leq m\leq 6\).

Note
For \(C_4\) the sphere \(S^{n\sigma+m\lambda}\) is represented by a vector {n,m} . More generally for \(C_{2^n}\) the sphere \(S^{t_1\sigma+\sum_it_i\lambda_i}\) is represented by {t_1,...,t_n}. This is specified in C2n.hpp.

To print all Mackey functors \(H_{\star}\) in the universal notation (see "Universal" Mackey functor notation) and for \(\star\) in the aforementioned range, use:

  std::cout << A << "\n";

The answer is of the form

The k=-9 homology of the -1,-4 sphere is 112#01

which means

\[H_{-9}(S^{-\sigma-4\lambda})= 112\#01\]

in our "universal notation".

You can survey the identified Mackey functors by:

std::cout << "The identified Mackey functors are: " << A.identified() << "\n\n\n\n";

(this will print one Mackey functor from each each equivalence class)

Factorization

The class Factorization computes the multiplication graph (see the page Factorization) given the "basic irreducibles".

In this case let us use \(a_{\sigma},u_{2\sigma},a_{\lambda},u_{\lambda}\) as our irreducibles:

std::vector<std::vector<int>> basic_irr = { {0, 1, 0}, {2, 2, 0}, {0, 0, 1}, {2, 0, 1} };
std::vector<std::string> basic_irr_names = {"asigma", "u2sigma", "alambda", "ulambda"};
Note
For any group \(G\), the degree of an element in \(H_kS^V\) is represented by a vector {k,t1,...,tn} where {t1,...,tn} represents \(S^V\).

To compute the multiplication graph in the range \(S^{n\sigma+m\lambda}\), $-5\leq n,m\leq 5$, use:

auto F = Factorization<group_t>(2, {-5, -5}, {5, 5}, basic_irr, basic_irr_names);

The 2 here signifies that we work on the top level of \(C_4\).

Note
For a group \(G=C_{p^n}\) the level corresponding to \(C_{p^n}/C_{p^i}\) corresponds to the integer \(i\).

Then

F.compute_with_sources({{0, 0, 0}}, {"1"});

computes the factorizations by connecting every node in the multiplication graph to \(1\) (if possible). To print the generator at degree \([3,1,0]\) use:

std::cout << "The generator(s) at degree 3,1,0 is (are): " << F.getname({ -2,-2,0 }) << "\n\n";
Note
getname returns a vector of strings as opposed to a single string, in case there are multiple generators in the given degree (i.e. if the homology group is not cyclic),
Warning
You need to make sure the vector you are passing to getname is within the range of spheres in the construction of F. This can be done using degreewithinrange

To print the names of all generators use:

std::cout << F << "\n\n";

The answer will be of the form

At degree -4,-2,-1 we have: 1*4/(u2sigma*ulambda)

or of the form:

At degree -7,-4,-4 we have: ???

The ??? means that the generator could not be obtained by multiplying/dividing the basic irreducibles with 1. This means that additional sources may be needed. To include the generator of \(H_{-3}S^{-2\lambda}\) as our source we use:

  F.compute_with_sources({{0,0,0},{-3,0,-2}}, {"1","s"});

where now both \(1\) and \(s\) are used as sources. With that extra source, the code

std::cout << F << "\n\n";

won't produce any ???.

To print the multiplication graph to a file and in the dot format use

std::ofstream file;
file.open("multgraph.dot");
file << F.graph;
file.close();

You can also print the shortest path tree to a file, which will be much simpler than the entire multiplication graph

file.open("shortestpaths.dot");
file << F.shortest_paths;
file.close();

The .dot files can be rendered to .svg files using Graphviz.

Multiplying generators

The class Factorization works by multiplying all generators of \(H_\star\) in a given range.

To multiply two specific generators together we use the function ROGreen. Example:

auto linear_combination = ROGreen<group_t>(2, {-4, -2, -1}, {2, 0,  1});

performs the operation

\[ H_0^{C_4}(S^{2\sigma-2\lambda}) \otimes H_{-4}^{C_4}(S^{-2\sigma-\lambda}) \to H_{-2}^{C_4}(S^{-2\sigma}) \\ a\otimes b\mapsto ab\]

where \(a,b\) are generators of the respective homology groups. Here:

  • The first argument of ROGreen indicates the level the generators live in.
  • The second and third arguments are the degrees of the two generators \(a,b\).
  • The result of the computation linear_combination is a row vector \([t_0,...,t_k]\) of integer entries representing that:

    \[ab=\sum_it_ig_i\]

    where \(g_i\) are the generators of the homology group the product lives in.

In our case \(H_{-2}^{C_4}(S^{-2\sigma}) \) is cyclic so linear_combination has length \(1\).

Using the Factorization object F from the previous examples, we can actually print the names of the generators being multiplied and the name of the generator in the degree of the product:

std::cout << F.getname({ -4,-2,-1 }) << " * " << F.getname({ 2,0,1 }) << " = ";
std::cout << linear_combination[0] << " * " << F.getname({ -2,-2,0 });

which will print out that:

\[\frac{4}{u_{2\sigma}u_{\lambda}}\cdot u_{\lambda}= 2\cdot \frac{2}{u_{2\sigma}}\]

Note
If the homology in the degrees of \(a\) or \(b\) is not cyclic, then we select \(a,b\) by providing two int arguments in RO::Green. For example, providing \(1,2\) selects the second and third generators \(a,b\) of the noncyclic groups respectively.

Massey products

The method ROMassey computes (triple) Massey products in the Green functor \(H_{\star}\). Example:

  auto Mass= mackey::ROMassey<group_t>(2,{0,1,0},{-3,-3,0},{2,2,0});

computes the Massey product \(\langle a_{\sigma},w_3,u_{2\sigma}\rangle \) and its indeterminacy.

As with the multiplicative structure, the Massey product is expressed in terms of a linear combination of the basis in the homology of the box product. But there's also indeterminacy to worry about. In this case,

  std::cout << Mass.indeterminacy;

prints out 1, so there is no indeterminacy, and we can print out the answer by:

    std::cout << "<" << F.getname({ 0, 0, 3 }) << " , " << F.getname({ -3, 0, -2 }) << " , ";
    std::cout << F.getname({ 2, 0, 1 }) << "> = " << Mass.basis[0] << " * " << F.getname({ 0,0,2 }); 

since the homology at degree {0,0,2} is cyclic (otherwise Mass.basis is a vector of size >1).

Note
We can also provide three optional int arguments at the end for selections, analogous to what we did in Multiplying generators (see Massey for more details).

Higher order groups

For groups beyond \(C_4\) it's possible for various identifications to fail. So let us set

typedef C8<int64_t> group2_t;

for \(C_8\) with \(\mathbf Z\) coefficients.

Then the code

AdditiveStructure<group2_t> A2({ -3, -3,-3 }, { 3, 3,3 });
std::cout << A2 << "\n\n";

can also produce output like:

The k=3  homology of the 3,1,-1 sphere is unknown 5

This means that the program couldn't write \(H_{3}(S^{3\sigma+\lambda_0-\lambda_1})\) in the "universal notation" and instead named it unknown Mackey functor with id 5. To print out the Mackey functor structure, us:

std::cout << "The unknown 5 is =\n" << A2.unknown()[5].print()<< "\n\n";

As for factorization, let us use the following basic irreducibles and sources over \(C_8\):

typedef std::vector<std::vector<int>> vv;
typedef std::vector<std::string> vs;
vv basic_irr2 = { {0,1,0,0},{0,0,1,0},{0,0,0,1},{2,2,0,0},{2,0,1,0},{2,0,0,1} };
vs basic_names2 = { "a2","a4","a8","u2","u4","u8" };
vv sources2 = { {0,0,0,0}, {-3,0,0,-2} };
vs source_names2 = { "1", "s"};

Then

auto F2 = Factorization<group2_t>(3, {-5,-5,-5 }, { 5, 5, 5 }, basic_irr2, basic_names2);
F2.compute_with_sources(sources2, source_names2);
std::cout << F2.disconnected_degrees().size() << "\n\n";

will print out 49, which is the number of generators that couldn't be connected to \(1\) or \(s\). There are two reasons that caused this:

  • The generators are close to the edge of the range of spheres hence multiplying them by the basic irreducibles takes the products outside of the range so they are not considered
  • Due to the presence of noncyclic groups, the program was not able to identify these generators (see A caveat).

The solution to the first problem is to increase the range of the spheres being used. To solve the second problem, we use triple products (see A caveat) via:

F2.pass_unidentified();

Once we do that,

std::cout << F2.disconnected_degrees().size() << "\n\n";

will print out 5.

Finally, if only the connectivity of the multiplication graph is desired, there is a specialized MultConnectivity class for that exact purpose.
For example,

auto MC = MultConnectivity<group2_t>(F2);
MC.compute_with_sources(sources2);
std::cout << MC.disconnected_degrees.size() << "\n";

will print \(0\), which means that all generators are connected to \(1,s\).

Serialization

In many cases it is desirable to save computational results in cold storage and then load them back as needed.

This library achieves serialization by calling the cereal library, which you'll need to include in your path. The serialization methods are found in the header Cerealizer.hpp so start with:

#include Serialization/Cerealizer.hpp

For example, say we have a Factorization object F that we want to save to a binary file. We can do that by:

save(F,"filename");

This actually saves the parent class MultTableData as opposed to the factorization object, since the fundamental data are in that class. As such, to load it use:

MultTableData<group_t> M;
load(M,"filename");
Note
The template parameter group_t must match with the template parameter of the saved object.

We can then construct F from M by:

Factorization<group_t> Fnew(std::move(M),basic_irr_names);

(the names of the basic irreducibles are not part of the data that was serialized). Then Fnew and F will be identical.