This is a Java program I wrote for a Google Foobar challenge ("Disorderly Escape") that counts matrix equivalence classes under row and column swaps. If you're here to see that, you can check out the foobar
directory. I've also since reorganized my code into a proper Java project.
Given an
The set of matrices defined by rows swaps and column swaps can be expressed using the symmetric groups
With this in mind, how can we count the equivalence classes of an
Where
The cardinality of a group can be thought of as the number of functions you can perform from one member of an equivalence group to another member of the same group. In this case, that's all the possible row swaps you can make (for a
The number of transformations fixed by
We therefore need to count the number of matrices left fixed after each row swap individually and divide by
How do we combine these two groups? We can take the Cartesian product group of the two groups
There are some things to point out in this new equation.
Consider a
If we take a look at the configuration with a single
In our problem, we consider all of these to be part of the same group. This means they only count for one equivalence class. Here is a list of one matrix from each of the total equivalence groups for the given parameters:
There are 7 in total. When I say "a list of one matrix", I mean we could have used any matrix from the same equivalence group to represent the group as a whole. Therefore, this list is valid, but we could have used
Let's use the same
We can already fill out
Now we need to iterate through all the possible row-column swap permutations. We'll define
We can now sum up all of these possibilities and divide by the 4 possible configurations of
With
This process was considerably longer than the simple process for a
As mentioned at the top, I originally encountered this problem in a level 5 Google Foobar challenge as the last problem I had to complete. As they give users the option to write their code in either Java 8 or Python 2, I picked Java to write this in and left my code in the foobar
directory. However, I would not recommend reading it to understand what's going on and instead direct you to the polished code in src
.
Since the numbers we're working with are ginormous, I make use of Java's BigInteger
class and had to create my own Rational
class for expressing really large fractions without losing accuracy to floating point precision errors. Such is the challenges of doing this in Java instead of Python. I'd mostly focus on the following classes if you want to learn what's going on:
impl/Solution.java
impl/utils/Symbol.java
impl/utils/SymbolPair.java
I also implemented a bunch of extraneous classes for testing/running solutions in a more general settings, so if you want to tinker with this to make it more efficient, expand functionality, or just play around, I've hopefully made that process a bit easier for you.
I've decided to update src
to Java 17 while keeping foobar
Java 8; keep this in mind if you plan on working with both. You cannot use Java 8 on src
as it makes use of later features like records.
Here are some helpful links for further reading on this topic: