#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct pair_hash {
    size_t operator()(pair<char,char> const &x) const {
        return x.first << CHAR_BIT | x.second;
    }
};

class mdview {
    private:
        vector<int> *oda;
    public:
        mdview(vector<int> &oda) : oda(&oda) {}
        size_t size() const { return oda->size()/2; }
        int const *operator [](int idx) const { return oda->data() + idx*2; }
};

// void print(mdview const &gv) {
//     for (size_t i = 0; i < gv.size()*2; i++) {
//         cerr << gv[0][i] << ",";
//     }
//     cerr << endl;
//
//     for (size_t i = 0; i < gv.size(); i++) {
//         cerr << "(" << gv[i][0] << "," << gv[i][1] << ") ";
//     }
//     cerr << endl;
// }

bool calc(vector<string> const &chars, mdview const &hgv, mdview const &wgv) {
    for (size_t hs = 0; hs < hgv.size(); hs++) {
        for (size_t ws = 0; ws < wgv.size(); ws++) {
            int y1 = hgv[hs][0];
            int x1 = wgv[ws][0];
            int y2 = hgv[hs][1];
            int x2 = wgv[ws][1];
            if (chars[y1][x1] != chars[y2][x2] || chars[y2][x1] != chars[y1][x2]) return false;
        }
    }
    return true;
}

pair<vector<int>,int> organize(vector<string> const &chars, vector<vector<unordered_map<pair<char,char>, int, pair_hash>>> const &pairs, int upto, bool is_h) {
    vector<int> gs(upto, -1);
    int g = 0;
    for (int i = 0; i < upto; i++) {
        if (gs[i] != -1) continue;
        for (int j = i+1; j < upto; j++) {
            if (gs[j] != -1) continue;
            bool ok = true;
            for (auto const &x: pairs[i][j]) {
                auto const &lkey = x.first;
                auto rkey = make_pair(lkey.second, lkey.first);
                if (!pairs[i][j].count(rkey) || x.second != pairs[i][j].at(rkey)) {
                    ok = false;
                    break;
                }
            }

            auto otpu = is_h ? chars[0].size() : chars.size();
            if (ok) for (int l = 0; l < j; l++) {
                if (l == i) continue;
                if (gs[l] != g) continue;
                bool same = true;
                for (size_t k = 0; k < otpu; k++) {
                    if (is_h) same = same && chars[l][k] == chars[j][k];
                    else      same = same && chars[k][l] == chars[k][j];
                }
                ok = ok && !same;
            }
            if (ok) gs[i] = gs[j] = g;
        }
        g++;
    }
    // cerr << "gs: ";
    // copy(gs.begin(), gs.end(), ostream_iterator<int>(cerr, ", "));
    // cerr << endl;
    if (count(gs.begin(), gs.end(), -1) > 1) {
        return make_pair(gs, -1);
    }
    return make_pair(gs, g);
}

// pair<vector<int>,int> organize(vector<map<char, int>> const &cnt, int upto) {
//     vector<int> gs(upto, -1);
//     int g = 0;
//     for (int i = 0; i < upto; i++) {
//         bool exists = false;
//         if (gs[i] != -1) continue;
//         for (int j = i+1; j < upto; j++) {
//             if (gs[j] != -1) continue;
//             if (cnt[i] == cnt[j]) {
//                 exists = true;
//                 gs[i] = gs[j] = g;
//             }
//         }
//         if (exists) g++;
//     }
//     if (count(gs.begin(), gs.end(), -1) > 1) return make_pair(gs, -1);
//     return make_pair(gs, g);
// }

class groupings_generator {
    private:
        mdview curr;
        vector<int> curr_flat;
        vector<pair<vector<int>::iterator, vector<int>::iterator>> range;

    public:
        groupings_generator(vector<vector<int>> const &orig) : curr(curr_flat) {
            curr_flat.reserve(12);
            for (auto const &r: orig) {
                for (auto x: r) {
                    curr_flat.push_back(x);
                }
            }

            auto it = curr_flat.begin();
            for (size_t i = 0; i < orig.size(); i++) {
                if (orig[i].size() > 2) {
                    range.push_back(make_pair(it, it + orig[i].size()));
                }
                sort(it, it + orig[i].size());
                it += orig[i].size();
            }
        }

        mdview const &get_curr() {
            // cerr << "curr_flat: ";
            // copy(curr_flat.begin(), curr_flat.end(), ostream_iterator<int>(cerr, ", "));
            // cerr << "curr: ";
            // for (int i = 0; i < curr.size(); i++) {
            //     cerr << "(" << curr[i][0] << "," << curr[i][1] << "), ";
            // }
            // cerr << endl;
            return curr;
        }
        bool gen_next() {
            bool flag = false;
            for (int i = range.size()-1; i >= 0; i--) {
                if (next_permutation(range[i].first, range[i].second)
                        && next_permutation(range[i].first, range[i].second)) {
                    flag = true;
                    break;
                }
            }
            curr = mdview(curr_flat);
            return flag;
        }
};

int main() {
    int h, w;
    cin >> h >> w;
    vector<string> chars(h);
    for (int i = 0; i < h; i++) {
        cin >> chars[i];
    }

    // vector<map<char,int>> cnth(h);
    // vector<map<char,int>> cntw(w);
    // for (int i = 0; i < h; i++) {
    //     for (int j = 0; j < w; j++) {
    //         cnth[i][chars[i][j]]++;
    //         cntw[j][chars[i][j]]++;
    //     }
    // }

    vector<vector<unordered_map<pair<char,char>, int, pair_hash>>> ph(h, vector<unordered_map<pair<char,char>,int,pair_hash>>(h));
    for (int i = 0; i < h; i++) {
        for (int j = i+1; j < h; j++) {
            for (int k = 0; k < w; k++) {
                ph[i][j][make_pair(chars[i][k], chars[j][k])]++;
            }
        }
    }
    vector<vector<unordered_map<pair<char,char>, int, pair_hash>>> pw(w, vector<unordered_map<pair<char,char>,int,pair_hash>>(w));
    for (int i = 0; i < w; i++) {
        for (int j = i+1; j < w; j++) {
            for (int k = 0; k < h; k++) {
                pw[i][j][make_pair(chars[k][i], chars[k][j])]++;
            }
        }
    }

    vector<int> hg, wg;
    int hgc, wgc;
    tie(hg, hgc) = organize(chars, ph, h, true);
    tie(wg, wgc) = organize(chars, pw, w, false);
    if (hgc == -1 || wgc == -1) { cout << "NO" << endl; return 0; }

    vector<vector<int>> hgv(hgc), wgv(wgc);
    for (int i = 0; i < h; i++) {
        if (hg[i] != -1) hgv[hg[i]].push_back(i);
    }
    for (int i = 0; i < w; i++) {
        if (wg[i] != -1) wgv[wg[i]].push_back(i);
    }

    // ll cnt = 0;
    groupings_generator hgen(hgv);
    groupings_generator wgen(wgv);
    do {
        auto const &hgv = hgen.get_curr();
        do {
            auto const &wgv = wgen.get_curr();

            if (calc(chars, hgv, wgv)) {
                cout << "YES" << endl;
                return 0;
            }
            // cerr << cnt++ << endl;
        } while (wgen.gen_next());
    // } while (hgen.gen_next());
    } while (false);

    cout << "NO" << endl;

    return 0;
}


Measured memory_bytes: 384