Mathematics 152
       Programming Project #3
            The Isomorphism between Permutation Groups and Matrices over Finite Fields

Revised: December 1, 2003

You will create a C++ program that lets you compute the inverse of a matrix in PSL(2,F), where F is a finite field, or to multiply two such matrices. Then you will associate a permutation with each such matrix and let the user verify that the group of permutations is isomorphic to the group of matrices.  If you are feeling ambitious, you could even display the two isomorphic groups SL(2,F4) and PSL(2,Z5) at the same time and have a four-way isomorphism.

These instructions will explain how to create the user-interface parts of the program that you may not have seen before.  After that, you are on your own.  You can reuse your previous code for multiplying permutations and for doing arithmetic in finite fields.

The programs used in class that multiply 2x2 matrices over F4 and Z5, "SL2F.exe and GL2Z5.exe", can be downloaded from the course Web site.
You can also download a copy of this document, from which you can paste code into your project as you are creating it.

1. By following steps 1-6 of the previous project with "GF" replaced by "Iso" (and "gf" by "iso" in file names), create a widget-based project named Iso.

2. Open up isobase.ui in Qt Designer. Change the caption of the form to "Isomorphism Demonstration."  If you are not working on the Science Center network, change the font to 12-point Lucidatypewriter.

3. In the upper right-hand corner of the dialog, place a button group box (icon to the right of Group Box), about 150x100, with the title "Galois Field". Inside the group box, place two radio buttons (icon is a black circle inside a white circle).  The top one should have the name RadioF4 and the text SL(2,F4).  The second one should have the name RadioF5 and the text PSL(2,Z5).  Choose Edit...Slots from the menu and add slots slotF4() and slotZ5().
Press F3 to enter connection mode and connect clicked() for RadioF4 to slotF4().
Again press F3 to enter connection mode and connect clicked() for RadioZ5 to slotZ5().

4. In the upper left-hand corner of the dialog, place a group box, about 180x270, with the title Matrix A. At the upper left corner of this group box, place a combo box (icon, to the left of the slider, looks like a list box with something on top of it). Make this 20 pixels high and half the width of the group box. Change its name to ComboA11.
With this combo box selected, press Ctrl-C to copy it.  Press Ctrl-V to paste a copy, and drag it to the right side of the top row of the group box.  Change the name to ComboA12, and Adjust the size of the group box so that the two combo boxes fit neatly.  Now copy two more combo boxes under the first two to complete the 2x2 matrix. Change their names to ComboA21 and ComboA22.
Beneath the two combo boxes, place a button with name ButtonCheck and text Read and Check.
Under the button, place a text label, large enough to show two lines of 10 characters, with name TextShowA. Change its palette background color to white.  Beneath this, put a text label with text "Permutation" and under that, a line edit with name EditPermA.
Choose Edit...Slots from the menu and add slot slotCheck().
Press F3 to enter connection mode and connect clicked() for ButtonCheck() to slotCheck().
Close QtDesigner, saving the .ui file.

5. Under the Classes tab, right-click on Classes. Choose New Class... from the drop-down menu. For the name of the class, choose Matrix2x2. There is no base class  Press OK to create the class.  Right-click on the name of this new class under the Classes taband add the following member variables:
  GFElement el11;
  GFElement el12;
  GFElement el21;
  GFElement el22;
  int prime;
  int power;

Just above the class declaration in Matrix2x2.h, insert the line
#include "gfelement.h"
From the main menu, choose Project...Add Existing Files... and insert the files gfelement.h and gfelement.cpp from your GF directory into the Iso directory.
As the last line of the function GFElement::init(), add
setValue();

This will initialize the element to [0]

Build your project.  If you have followed instructions carefully, you should see the class GFElement under the Classes Tab.
 

6. Add the following function to the class Matrix2x2 to initialize all the elements of a matrix for a specific finite field.
void Matrix2x2::init(int pr, int pow){
  prime = pr;
  power = pow;
  el11.init(pr,pow);
  el21.init(pr,pow);
  el12.init(pr,pow);
  el22.init(pr,pow);
}

7. In class Iso, insert the member variable
Matrix2x2 matrixA;
Then add slotCheckA() with the following code:

void Iso::slotCheckA()
{
  int index = ComboA11->currentItem();
  matrixA.el11.setValue(index%matrixA.prime,index/matrixA.prime);
  index = ComboA12->currentItem();
  matrixA.el12.setValue(index%matrixA.prime,index/matrixA.prime);
  index = ComboA21->currentItem();
  matrixA.el21.setValue(index%matrixA.prime,index/matrixA.prime);
  index = ComboA22->currentItem();
  matrixA.el22.setValue(index%matrixA.prime,index/matrixA.prime);
  if (matrixA.checkDeterminant()) {
    TextShowA->setText(matrixA.boxText());
  }
  else QMessageBox::warning(this,"Invalid Matrix","This matrix does not have determinant 1.  Change an entry so that the the determinant is 1");
}

At the top of iso.cpp
#include <qlabel.h>
#include <qmessagebox.h>
 

8. In the class Matrix2x2, add the member functions

GFElement Matrix2x2::determinant(){
  GFElement det = el11*el22 - el21*el12;
  return det;
}

bool Matrix2x2::checkDeterminant(){
//The following assumes power < 3
    return (determinant().c[0] == 1 && determinant().c[1] == 0 );
}
 

The job of the second function is to check the data supplied by the user to make sure that the matrix has determinant 1.

In the case of  Z5 you may also want to multiply the entire matrix by [4] if necessary to make it be the standard representative of its equivalence class.  A reasonable criterion for "standard" is that the first nonzero entry should be [1] or [2] in the case of Z5.  If you do not do this you will end up with a homomorphism of SL(2,Z5) with A5, which is still OK.
 

9. Add the following functions to the class Matrix2x2.  These format a matrix so that it can be displayed in a text label.
QString Matrix2x2::extend(QString s, uint size){
  while (s.length() < size)
     s += " ";
  return s;
}

QString Matrix2x2::boxText(){
  return extend(el11.asText(),6) + el12.asText() + "\n" +  extend(el21.asText(),6) + el22.asText();
}

10. Add the following function to the class Iso.  This puts the correct strings for the chosen Galois field into a combo box.

void Iso::fillComboBox(QComboBox* box, Matrix2x2& m){
  GFElement entry;
  entry.init(m.prime,m.power);
  int c1max = 1;
  if (m.power > 1) {
    c1max = m.prime;
  }
  box->clear();
  for (int i = 0; i < c1max; i++) {
    for (int j = 0; j < m.prime; j++) {
      entry.setValue(j,i);
      box->insertItem(entry.asText());
    }
  }
}
At the top of iso.h
#include <qcombobox.h>
#include "matrix2x2.h"

12. In class Iso, override the two remaining virtual slot functions from IsoBase, with the following code:

void Iso::slotF4(){
    matrixA.init(2,2);
    fillComboBox(ComboA11, matrixA);
    fillComboBox(ComboA12, matrixA);
    fillComboBox(ComboA21, matrixA);
    fillComboBox(ComboA22, matrixA);
}
/** No descriptions */
void Iso::slotZ5(){
    matrixA.init(5,1);
    fillComboBox(ComboA11, matrixA);
    fillComboBox(ComboA12, matrixA);
    fillComboBox(ComboA21, matrixA);
    fillComboBox(ComboA22, matrixA);
}

13. At this point you can build and run the project. For either field, if you type in a matrix whose determinant is [1], you should see it nicely displayed in the two-line edit control. Otherwise you will see a message box complaining that the determinant is not [1].

14. From this point you are on your own!  Here are some features that you might include:
For 6 points, add a class Vector2 that represents a two-component vector over a finite field.  It might be a good idea to add a function to this class that returns a "line name" for each vector. A good way to number the lines is to the first one be ([1] [0]), with name "0" and the others be ( [0] [1]), ([1], [1]), etc. with names '1', '2',.... This is slightly different from the numbering that was done in class, bt it is more systematic.
A constructor that constructs a Vector2 with specified power, prime, and line name may also be useful.

For 7 points, compute the action of MatrixA on each of the lines in the 2x2 vector space over the field and thereby associate a permutation with the matrix.  A function like
char Matrix2x2::actOnLine(char i)
where i is the "line name," will be all that you need.  The code to convert the results of this function into the cycle representation of the permutation is something that you wrote for project 1, though you may need to make a tiny modification for the symbol '0'.

For 8 points, have the slotCheckA() function also report the order of the matrix in a text label and compute and display the inverse of the matrix..

For 9 points, add a second matrix B and compute the product AB and the product of the corresponding permutations.  You can copy the code that multiplies permutations from project 1, with small modifications to take account of the symbol '0'. In Qt Designer, you can use Ctrl-C and Ctrl-V to copy the Matrix A group box and all its contents.

For 10 points, add Z7 as an additional choice for the finite field. This may be very easy!

For 11 points, make it possible for the user to type in the permutation instead of the matrix and press a button to generate a matrix of determinant 1 that gives rise to the specified permutation.  This presents an interesting mathematical problem, since the permutation only tells you a vector proportional to the result of a matrix acting on a given vector.

For 12 points, add F9 .The permutations now involve ten lines, and you have reached the limit of what you can do with the symbols 0 through 9.

For 14 points, add F8 .This will be messy, since some of the existing code assumes power < 3 and Fhas prime =2, power = 3.