Bar Codes

AUTHORS:

The two classes provided in this module are used to store and display ‘persistent group cohomology’. Persistent group cohomology was introduced by [EllisKing].

The basic idea is as follows: Any normal series of a group gives rise to a chain of inclusion and quotient maps, which in turn give induced homomorphisms in cohomology. The degree \(d\) bar code associated with the normal series is an upper triangular non-negative integer matrix, telling how many cocycles of degree \(d\) ‘survive’ how long under the induced maps.

It turns out that these simple collections of integers allow to distinguish between cohomology rings, even if the rings seem fairly similar (same Poincaré series, same number of generators and relations sorted by degree, same depth) and even if the normal series of the two groups are essentially the same.

EXAMPLES:

We work here with groups of order 64, that are part of the cohomology data base shipped with this package.

sage: from pGroupCohomology import CohomologyRing
sage: H158 = CohomologyRing(64,158)
sage: H160 = CohomologyRing(64,160)

The Poincaré series, the \(a\)-invariants, the degrees of generators and of relations of the cohomology rings coincide:

sage: H158.poincare_series()
(t^4 + t^3 + t^2 + t + 1)/(t^6 - 2*t^5 + 3*t^4 - 4*t^3 + 3*t^2 - 2*t + 1)
sage: H160.poincare_series()
(t^4 + t^3 + t^2 + t + 1)/(t^6 - 2*t^5 + 3*t^4 - 4*t^3 + 3*t^2 - 2*t + 1)
sage: H158.degvec
[4, 4, 1, 1, 1, 3, 3]
sage: H160.degvec
[4, 4, 1, 1, 1, 3, 3]
sage: H158.set_ring()
sage: [singular('deg(%s)'%r) for r in H158.rels()]
[2, 2, 3, 3, 4, 4, 5, 6, 6, 6]
sage: H160.set_ring()
sage: [singular('deg(%s)'%r) for r in H160.rels()]
[2, 2, 3, 3, 4, 4, 5, 6, 6, 6]
sage: H158.a_invariants()
[-Infinity, -Infinity, -2]
sage: H160.a_invariants()
[-Infinity, -Infinity, -2]

We consider here the bar codes associated with the upper central series. It turns out that the non-trivial terms of the upper central series and the resulting factor groups are isomorphic:

sage: G158 = libgap.SmallGroup(64,158)
sage: G160 = libgap.SmallGroup(64,160)
sage: [(G.IdGroup(), (G158/G).IdGroup()) for G in G158.UpperCentralSeries()]
[([ 64, 158 ], [ 1, 1 ]),
 ([ 16, 2 ], [ 4, 2 ]),
 ([ 4, 2 ], [ 16, 11 ]),
 ([ 1, 1 ], [ 64, 158 ])]
sage: [(G.IdGroup(), (G160/G).IdGroup()) for G in G160.UpperCentralSeries()]
[([ 64, 160 ], [ 1, 1 ]),
 ([ 16, 2 ], [ 4, 2 ]),
 ([ 4, 2 ], [ 16, 11 ]),
 ([ 1, 1 ], [ 64, 160 ])]

Nevertheless, the groups can be distinguished using the bar codes associated with the upper central series:

sage: B158 = H158.bar_code('UpperCentralSeries')
sage: B160 = H160.bar_code('UpperCentralSeries')
sage: B158 == B160
False

Indeed, the bar codes differ in degree 3; graphically:

sage: ascii_art(B158[3])
        *
        *
      *-*
      *-*
      *
      *
      *
      *
      *
      *
    *-*
    *-*
    *
    *
  *
  *
  *
  *
*
*
*
*
sage: ascii_art(B160[3])
        *
        *
      *-*
      *
      *
      *
      *
      *
      *
      *
    *-*-*
    *-*
    *
  *-*
  *
  *
  *
*
*
*
*

These pictures (bar codes) can be interpreted as follows. Let \(G\) be a finite \(p\)-group and let \(G=G_0 > G_1 > ... > G_n > 1\) be a normal series; in our example, we have \(n=2\). The first \(n+1\) columns of the bar code correspond to the normal subgroups groups \(G_n, G_{n-1},..., G_0\), while the last \(n\) columns correspond to the factor groups \(G/G_n, G/G_{n-1},..., G/G_1\). We consider the sequence of group homomorphisms given by inclusions and quotients. The stars in the bar code correspond to basis vectors of the degree \(d\) part of the cohomology rings of the respective groups. Stars are connected by a line (i.e., a hyphen) if the corresponding basis vectors are mapped to each other by the induced maps (which of course go from right to left).

As we have mentioned above, the bar code is determined by an upper triangular ‘persistence matrix’, which is as follows in degree 3:

sage: B158[3].matrix()
[ 4  0  0  0  0]
[ 0  4  0  0  0]
[ 0  0  4  2  0]
[ 0  0  0 10  2]
[ 0  0  0  0  4]
sage: B160[3].matrix()
[ 4  0  0  0  0]
[ 0  4  1  0  0]
[ 0  0  4  2  1]
[ 0  0  0 10  2]
[ 0  0  0  0  4]

As usual, the sequence of integers in increasing degrees gives rise to a Poincaré series. So, in fact we get an upper triangular persistence matrix whose coefficients are rational functions. We show how these look in position (2,4):

sage: B158.matrix()[2,4]
2*t^2 + 2*t + 1
sage: B160.matrix()[2,4]
t^3 + 2*t^2 + 2*t + 1
class pGroupCohomology.barcode.BarCode(L, **MetaData)

Bar codes (persistent group cohomology).

A bar code in a fixed degree is encoded by an upper triangular matrix of integers and can be depicted by arrangement of bars of different length. The full bar code combines the information for all degrees, by means of Poincaré series.

EXAMPLES:

This class was designed for use in persistent group cohomology. So, we take an example from this context. See bar_code() for the theoretical background.

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries')    # indirect doctest
sage: B
Persistence data for H^*(D8; GF(2)) associated with UpperCentralSeries

The persistence data are encoded in an upper triangular matrix whose entries are Poincaré series:

sage: B.matrix()
[       1/(-t + 1)      -1/(t^2 - 1)                 1]
[                0 1/(t^2 - 2*t + 1)  (-t - 1)/(t - 1)]
[                0                 0 1/(t^2 - 2*t + 1)]

The bar code in each degree can be extracted from the Poincaré series:

sage: B[1]
Barcode of degree 1 for H^*(D8; GF(2)) associated with UpperCentralSeries
sage: ascii_art(B[2])
    *
  *-*
  *-*
*-*
sage: B[2].matrix()
[1 1 0]
[0 3 2]
[0 0 3]
sage: B[15].matrix()
[ 1  0  0]
[ 0 16  2]
[ 0  0 16]
data()

Return the defining data of self as a sorted list.

EXAMPLES:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries')
sage: B
Persistence data for H^*(D8; GF(2)) associated with UpperCentralSeries
sage: B.data()
[((-1, -1), 1/(-t + 1)),
 ((-1, 0), -1/(t^2 - 1)),
 ((-1, 1), 1),
 ((0, 0), 1/(t^2 - 2*t + 1)),
 ((0, 1), (-t - 1)/(t - 1)),
 ((1, 1), 1/(t^2 - 2*t + 1))]
matrix()

Return the persistence matrix of self.

EXAMPLES:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries')
sage: B.matrix()
[       1/(-t + 1)      -1/(t^2 - 1)                 1]
[                0 1/(t^2 - 2*t + 1)  (-t - 1)/(t - 1)]
[                0                 0 1/(t^2 - 2*t + 1)]
show(*args, **kwds)

Show a 3D picture of self.

INPUT:

  • dmin (default = 1): optional non-negative integer, the lowest shown degree
  • dmax (default = 10): optional non-negative integer, the highest shown degree

The resulting picture combines the planar bar codes for each degree between dmin and dmax to a 3-dimensional arrangement of bars.

TESTS:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(16,3)
sage: H.make()
sage: B = H.bar_code('LowerCentralSeries')
sage: show(B,dmin=3,dmax=15)
<html><script type="math/tex">\newcommand{\Bold}[1]{\mathbf{#1}}\verb|Persistence|\phantom{\verb!x!}\verb|data|\phantom{\verb!x!}\verb|for|\phantom{\verb!x!}\verb|H^*(SmallGroup(16,3);|\phantom{\verb!x!}\verb|GF(2))|\phantom{\verb!x!}\verb|associated|\phantom{\verb!x!}\verb|with|\phantom{\verb!x!}\verb|LowerCentralSeries|</script></html>

For seeing a nice picture, you should instead do B.show(dmin=3, dmax=15).

class pGroupCohomology.barcode.BarCode2d(L, **MetaData)

Integer valued bar codes (bar code in a single degree).

A bar code in a fixed degree is encoded by an upper triangular matrix of integers and can be depicted by arrangement of bars of different length.

EXAMPLES:

This class was designed for use in persistent group cohomology. So, we take an example from this context. See bar_code() for the theoretical background.

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries')  # indirect doctest
sage: B
Persistence data for H^*(D8; GF(2)) associated with UpperCentralSeries
sage: B[3]
Barcode of degree 3 for H^*(D8; GF(2)) associated with UpperCentralSeries
sage: ascii_art(B[3])
    *
    *
  *-*
  *-*
  *
  *
*
sage: B[3].matrix()
[1 0 0]
[0 4 2]
[0 0 4]
add_metadata(key, datum)

Add further information on the bar code.

NOTE:

Currently, only the meta data degree, ring and command are used. But further meta data are, in principle, possible.

EXAMPLES:

sage: from pGroupCohomology.barcode import BarCode2d
sage: B = BarCode2d([((0,0),1)])
sage: B
Barcode
sage: B.add_metadata('degree',5)
sage: B
Barcode of degree 5
sage: B.add_metadata('ring','some fancy ring')
sage: B
Barcode of degree 5 for some fancy ring
sage: B.add_metadata('command','some normal series')
sage: B
Barcode of degree 5 for some fancy ring associated with some normal series
data()

Return the defining data of self as a sorted list.

EXAMPLES:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries',degree=3)
sage: B
Barcode of degree 3 for H^*(D8; GF(2)) associated with UpperCentralSeries
sage: B.data()
[((-1, -1), 1),
 ((-1, 0), 0),
 ((-1, 1), 0),
 ((0, 0), 4),
 ((0, 1), 2),
 ((1, 1), 4)]
matrix()

Return the persistence matrix of self.

EXAMPLES:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries',degree=3)
sage: B.matrix()
[1 0 0]
[0 4 2]
[0 0 4]
plot(*args, **kwds)

Produce a picture of the bar code.

TESTS:

sage: from pGroupCohomology import CohomologyRing
sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
sage: H = CohomologyRing(8,3)
sage: H.make()
sage: B = H.bar_code('UpperCentralSeries',degree=3)
sage: plot(B)     # render
Graphics object consisting of 7 graphics primitives