Problem (Euler, 1782). Six regiments each send six officers of six different ranks. Can the 36 officers stand in a square so that every row and every column contains each regiment once and each rank once?

Answer. No. The ranks form a Latin square (each symbol once per row and column), the regiments form another, and the requirement that every (rank, regiment) pair appears exactly once says the two squares are orthogonal. Orthogonal Latin squares (Graeco-Latin squares) exist for every order except 2 and 6.

Order Mutually orthogonal Latin squares (MOLS)Source
prime power , the maximum possiblefinite field:
(prime powers)at least MacNeish: Kronecker products
at least 2MacNeish (every prime-power factor is )
1 (no orthogonal pair)trivial
1 (no orthogonal pair)Tarry (1900); exhaustive search below
, at least 2Bose, Shrikhande and Parker (1959), disproving Euler’s conjecture
any at most normalization argument
123456
reduced Latin squares (first row and column in order)1114569408
all Latin squares reduced1212576161 280812 851 200
using Square = vector<vector<int>>;
 
// Finite field GF(p^k): elements 0..q-1 are polynomials over Z_p written in base p.
struct GF {
    int p, k, q; vector<vector<int>> add, mul;
    GF(int p, int k) : p(p), k(k), q(1) {
        for (int i = 0; i < k; i++) q *= p;
        auto digits = [&](int x) { vector<int> d(k); for (int i = 0; i < k; i++) d[i] = x % p, x /= p; return d; };
        auto pmul = [&](const vector<int>& a, const vector<int>& b) { vector<int> c(sz(a) + sz(b) - 1); for (int i = 0; i < sz(a); i++) for (int j = 0; j < sz(b); j++) c[i + j] = (c[i + j] + a[i] * b[j]) % p; return c; };
        auto reduce = [&](vector<int> c, const vector<int>& f) {   // c mod monic f of degree k
            for (int i = sz(c) - 1; i >= k; i--) if (int t = c[i]) for (int j = 0; j <= k; j++) c[i - k + j] = ((c[i - k + j] - t * f[j]) % p + p) % p;
            c.resize(k); return c;
        };
        vector<int> f;                                         // monic irreducible of degree k: no nonzero x has x * y = 0
        for (int low = 0; low < q && f.empty(); low++) {
            vector<int> g = digits(low); g.push_back(1); bool ok = true;
            for (int x = 1; x < q && ok; x++) for (int y = 1; y < q && ok; y++) {
                auto r = reduce(pmul(digits(x), digits(y)), g); ok = *max_element(all(r)) > 0;
            }
            if (ok) f = g;
        }
        add.assign(q, vector<int>(q)); mul = add;
        for (int x = 0; x < q; x++) for (int y = 0; y < q; y++) {
            auto a = digits(x), b = digits(y); int s = 0, m = 0;
            auto r = reduce(pmul(a, b), f);
            for (int i = k - 1; i >= 0; i--) s = s * p + (a[i] + b[i]) % p, m = m * p + r[i];
            add[x][y] = s; mul[x][y] = m;
        }
    }
    vector<Square> mols() const {                              // the q - 1 squares L_a(x, y) = a x + y
        vector<Square> res;
        for (int a = 1; a < q; a++) { Square L(q, vector<int>(q)); for (int x = 0; x < q; x++) for (int y = 0; y < q; y++) L[x][y] = add[mul[a][x]][y]; res.push_back(L); }
        return res;
    }
};
 
Square kronecker(const Square& A, const Square& B) {           // order |A| * |B|; preserves orthogonality pairwise
    int a = sz(A), b = sz(B); Square C(a * b, vector<int>(a * b));
    for (int i = 0; i < a * b; i++) for (int j = 0; j < a * b; j++) C[i][j] = A[i / b][j / b] * b + B[i % b][j % b];
    return C;
}
 
bool orthogonal(const Square& A, const Square& B) {
    int n = sz(A); vector<char> seen(n * n, 0);
    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { int x = A[i][j] * n + B[i][j]; if (seen[x]) return false; seen[x] = 1; }
    return true;
}
 
// Orthogonal mate of L: partition the cells into n disjoint transversals (one cell per row and column, all symbols).
// Returns the mate, or an empty square if none exists.
Square orthogonalMate(const Square& L) {
    int n = sz(L); vector<vector<int>> tr; vector<int> perm(n); iota(all(perm), 0);
    do { int used = 0; bool ok = true; for (int i = 0; i < n && ok; i++) { ok = !(used >> L[i][perm[i]] & 1); used |= 1 << L[i][perm[i]]; } if (ok) tr.push_back(perm); }
    while (next_permutation(all(perm)));
    vector<vector<int>> byFirst(n); for (int t = 0; t < sz(tr); t++) byFirst[tr[t][0]].push_back(t);
    vector<int> colUsed(n, 0), chosen;                         // colUsed[i]: columns of row i already taken
    auto go = [&](auto&& self, int c) -> bool {                // the transversal through cell (0, c)
        if (c == n) return true;
        for (int t : byFirst[c]) {
            bool ok = true; for (int i = 0; i < n && ok; i++) ok = !(colUsed[i] >> tr[t][i] & 1);
            if (!ok) continue;
            for (int i = 0; i < n; i++) colUsed[i] |= 1 << tr[t][i];
            chosen.push_back(t);
            if (self(self, c + 1)) return true;
            chosen.pop_back(); for (int i = 0; i < n; i++) colUsed[i] ^= 1 << tr[t][i];
        }
        return false;
    };
    if (!go(go, 0)) return {};
    Square M(n, vector<int>(n)); for (int s = 0; s < n; s++) for (int i = 0; i < n; i++) M[i][tr[chosen[s]][i]] = s;
    return M;
}

Running orthogonalMate on all 9408 reduced Latin squares of order 6 finds no mate (a few seconds), which settles Euler’s problem.