#if 1
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <array>
#include <deque>
#include <algorithm>
#include <utility>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <numeric>
#include <assert.h>
#include <bitset>
#include <list>

auto& in = std::cin;
auto& out = std::cout;
#define all(C) std::begin(C), std::end(C)
const double PI = 3.141592653589793238462643383279502884197169399375105820974944;


template<typename T, typename U>
std::enable_if_t<std::rank<T>::value == 0> fill_all(T& arr, const U& v) {
	arr = v;
}
template<typename ARR, typename U>
std::enable_if_t<std::rank<ARR>::value != 0> fill_all(ARR& arr, const U& v) {
	for (auto& i : arr) {
		fill_all(i, v);
	}
}

int32_t H, W;
char map[20][20];
int32_t pair[20];
std::string map2[20];
std::string map3[20];
std::string map4[20];
int dp[1 << 12];
bool func(std::bitset<12> rem)
{
	if (rem == 0) {
		return true;
	}
	if (dp[rem.to_ulong()] != -1) { return dp[rem.to_ulong()] != 0; }
	if(rem.count() == 1) {
		size_t i = 0;
		for (; rem[i]!=true; i++) { }
		bool ok = true;
		for (size_t k = 0; k < H; k++)
		{
			if (map[k][i] == map[pair[k]][i]) {

			}
			else {
				ok = false;
			}
		}
		return dp[rem.to_ulong()]=ok;
	}

	for (size_t i = 0; i < 12; i++)
	{
		if (rem[i])
		{
			rem[i] = false;

			for (size_t j = 0; j < 12; j++)
			{
				if (rem[j])
				{
					rem[j] = false;
					bool ok = true;
					for (size_t k = 0; k < H; k++)
					{
						if (map[k][i] == map[pair[k]][j]) {

						}
						else {
							ok = false;
						}
					}
					if (ok) {
						if (func(rem)) { return  dp[rem.to_ulong()] = true; }
					}
					rem[j] = true;
				}
			}

			rem[i] = true;
		}
	}

	dp[rem.to_ulong()] = 0;
	return false;
}

bool is_one[20];
bool func_2(std::bitset<12> rem)
{
	if (rem == 0) {
		fill_all(dp, -1);
		return func((1 << W) - 1);
	}
	if (rem.count() == 1) {
		size_t i = 0;
		for (; rem[i] != true; i++) {}
		pair[i] = i;
		fill_all(dp, -1);
		return func((1 << W) - 1);
	}

	for (size_t i = 0; i < 12; i++)
	{
		if (is_one[i]) { continue; }
		if (rem[i])
		{
			rem[i] = false;

			for (size_t j = i+1; j < 12; j++)
			{
				if (rem[j] && map2[i] == map2[j]) {
					rem[j] = false;
					pair[i] = j;
					pair[j] = i;
					if (func_2(rem)) { return true; }
					rem[j] = true;
				}
			}

			break;
		}
	}
	return false;
}

int main()
{
	using std::endl;
	in.sync_with_stdio(false);
	out.sync_with_stdio(false);
	in.tie(nullptr);
	out.tie(nullptr);

	in >> H >> W;
	for (int32_t i = 0; i < H; i++)
	{
		in >> map[i];
	}

	for (int32_t i = 0; i < H; i++) {
		map2[i] = map[i];
		std::string& tmp = map2[i];
		std::sort(tmp.begin(), tmp.end());
	}
	for (int32_t i = 0; i < W; i++)
	{
		std::string& tmp = map3[i];
		for (int32_t k = 0; k < H; k++) { tmp += map[k][i]; } map4[i] = map3[i];
		std::sort(tmp.begin(), tmp.end());
	}
	int32_t one_H = H % 2;
	for (int32_t i = 0; i < H; i++)
	{
		bool ok = false;
		for (int32_t j = 0; j < H; j++)
		{
			if (i != j && map2[i] == map2[j]) {
				ok = true;
				break;
			}
		}
		if (!ok) {
			if (one_H == 0) {
				out << "NO" << endl; return 0;
			}
			is_one[i] = true;
			one_H--;
		}
	}
	int32_t one_W = W % 2;
	for (int32_t i = 0; i < W; i++)
	{
		bool ok = false;
		for (int32_t j = 0; j < W; j++)
		{
			if (i != j && map3[i] == map3[j]) {
				ok = true;
				break;
			}
		}
		if (!ok) {
			if (one_W == 0) {
				out << "NO" << endl; return 0;
			}
			one_W--;
		}
	}

	if (func_2((1 << H) - 1)) {
		out << "YES"<<endl;
	}
	else {
		out << "NO" << endl;
	}


	return 0;
}
#endif


Measured memory_bytes: 256