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

typedef long long ll;
 
using tpl = tuple<int, int, int>;
typedef pair<int,int> pii;

void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}


/*
  以下は使わない行、列を最初に決めるように修正しないとだめ。
  決めた後、のこりを埋めていく形で。
 */

int H, W;
char S[20][20];
bool used_col[21];
bool used_row[21];
pii col_pair[21];
bool is_usable_row_pair[21][21];
bool no_sel_row[21];

bool perm2(int depth){
    if(depth == H / 2){
        // 基底に達したらOK
        return true;
    }
    else{
        int start = -1;
        // 使っていない一番左の要素は確定
        for(int i = 0; i < H; i++){
            if(used_row[i]) continue;
            start = i;
            break;
        }
        used_row[start] = true;
        for(int i = start + 1; i < H; i++){
            if(used_row[i]) continue;

            if(!is_usable_row_pair[start][i]) continue;

            used_row[i] = true;
            if(perm2(depth + 1))
                return true;
            used_row[i] = false;
        }
        used_row[start] = false;

        return false;
    }
}

bool perm(int depth, int no_sel_col){
    if(depth == W / 2){
        // 今確定したcolのペアのリスト対して、可能な行の選び方を調べる
        memset(is_usable_row_pair, 0, sizeof(is_usable_row_pair));
        for(int r1 = 0; r1 < H; r1++){
            for(int r2 = 0; r2 < H; r2++){
                if(r1 == r2) continue;
                bool ok = true;
                for(int i = 0; i < W / 2; i++){
                    int c1 = col_pair[i].first;
                    int c2 = col_pair[i].second;
                    if(!(S[r1][c1] == S[r2][c2] && S[r1][c2] == S[r2][c1])){
                        ok = false;
                    }
                }

                if(W % 2){
                    // 選ばれなかった列に対して(あれば)、可能なr1とr2の組を調べておく
                    ok &= (S[r1][no_sel_col] == S[r2][no_sel_col]);
                }
                is_usable_row_pair[r1][r2] = ok;
            }
        }

        if(H % 2){
            // ある行について、この列の選び方で問題なく選べるか調べておく
            for(int r1 = 0; r1 < H; r1++){
                bool ok = true;
                for(int i = 0; i < W / 2; i++){
                    int c1 = col_pair[i].first;
                    int c2 = col_pair[i].second;
                    if(!(S[r1][c1] == S[r1][c2])){
                        ok = false;
                    }
                }
                if(ok){
                    used_row[r1] = true;
                    if(perm2(0)){
                        return true;
                    }
                    used_row[r1] = false;
                }
            }
            return false;
        }
        else
            return perm2(0);
    }
    else{
        int start = -1;
        // 使っていない一番左の要素は確定
        for(int i = 0; i < W; i++){
            if(used_col[i]) continue;
            start = i;
            break;
        }
        used_col[start] = true;
        for(int i = start + 1; i < W; i++){
            if(used_col[i]) continue;
            used_col[i] = true;
            col_pair[depth] = pii(start, i);
            if(perm(depth + 1, no_sel_col))
                return true;
            used_col[i] = false;
        }
        used_col[start] = false;
    }
    return false;
}

bool solve(){
    if(W % 2){
        for(int j = 0; j < W; j++){
            used_col[j] = true;
            if(perm(0, j)) return true;
            used_col[j] = false;
        }
        return false;
    }
    else{
        return perm(0, 0);
    }
}

int main(){
    cin >> H >> W;
    for(int i = 0; i < H; i++) cin >> S[i];

    if(solve()){
        cout << "YES" << endl;
    }
    else{
        cout << "NO" << endl;
    }

    return 0;
}


Measured memory_bytes: 256