#include <iostream>
#include <vector>

/*さいころの面の数*/
const unsigned int FACE_SIZE = 6;
const unsigned int ROT_MAX = 4;

/*さいころの面の位置と、配列の番号の対応*/
enum FaceLabel{ TOP, FRONT, RIGHT, LEFT, REAR, BOTTOM };
enum Direct{ DIR_X, DIR_Y, DIR_Z };

class Dice{
private:
	/*face[i]はi面の数字
	*iは{ TOP, FRONT, RIGHT, LEFT, REAR, BOTTOM }のどれかを取る*/
	int face[FACE_SIZE];
	/*swapFace：引数で指定した順番にfaceを入れ替える関数*/
	void swapFace(int[FACE_SIZE]);
	bool checkAllFace(int[FACE_SIZE]);
	bool subMatchFace(int[FACE_SIZE]);
public:
	/*Dice():入力された6つの数値でfaceを初期化*/
	Dice();
	/*Dice::turn：引数で指定された方向にさいころを転がす*/
	void turn(Direct, int);
	/*Dice::turn：指定された上面、前面, 右面になるようにさいころを転がす
	*サイコロの3面が決まれば、サイコロの6面すべてが確定する*/
	bool turn(int[FACE_SIZE]);
	bool matchAllFace(int[FACE_SIZE]);
	int getPip(FaceLabel label){ return Dice::face[label]; }
	int* getAllPip(){ return Dice::face; };
};

/*Dice():入力された6つの数値でfaceを初期化*/
Dice::Dice(){
	for (size_t i = 0; i < FACE_SIZE; i++)
	{
		std::cin >> face[i];
	}
}

/*swapFace：引数で指定した配列の順番にfaceを入れ替える関数
*配列の中身が{ LEFT, FRONT, TOP, BOTTOM, REAR, RIGHT }なら、
*face[TOP]をface[LEFT]に、face[FRONT]はそのまま、face[RIGHT]をface[TOP]に・・・
*というように入れ替える
*参考： enum FaceLabel{ TOP, FRONT, RIGHT, LEFT, REAR, BOTTOM }
*/
void Dice::swapFace(int* afterFace){
	int tmp[FACE_SIZE];									//変更前のさいころの面を保存する一時変数
	for (size_t faceNum = 0; faceNum < FACE_SIZE; faceNum++)
	{
		tmp[faceNum] = Dice::face[faceNum];
	}
	for (size_t faceNum = 0; faceNum < FACE_SIZE; faceNum++)
	{
		//faceNum面の数字を更新する
		int num = afterFace[faceNum];
		Dice::face[faceNum] = tmp[num];
	}
}

//commandで指定された方向にさいころを転がす
void Dice::turn(Direct command, int times = 1){
	for (size_t i = 0; i < times; i++)
	{
		//右手系x座標の正方向への回転
		if (command == DIR_X){
			int afterFace[FACE_SIZE] = { RIGHT, FRONT, BOTTOM, TOP, REAR, LEFT };
			Dice::swapFace(afterFace);
		}
		//右手系y座標の正方向への回転
		else if (command == DIR_Y){
			int afterFace[FACE_SIZE] = { REAR, TOP, RIGHT, LEFT, BOTTOM, FRONT };
			Dice::swapFace(afterFace);
		}
		//右手系z座標の正方向への回転
		else if (command == DIR_Z){
			int afterFace[FACE_SIZE] = { TOP, LEFT, FRONT, REAR, RIGHT, BOTTOM };
			Dice::swapFace(afterFace);
		}
	}
}

//引数で、揃えたい面すべてを指定する
//すべての面が、指定された数字にそろっていたらtrue
//違うならfalseを返す
bool Dice::checkAllFace(int faces[FACE_SIZE]){
	for (size_t i = 0; i < FACE_SIZE; i++)
	{
		if (Dice::face[i] != faces[i]){
			return false;
		}
	}
	return true;
}

//引数で指定された面になるように回転させる
//できたならtrue,できないならfalseを返す
//すべてのサイコロの向きを調べる
bool Dice::matchAllFace(int faces[FACE_SIZE]){

	//ラベル1,4,5(現在の上面,背面、左面)が上面に来た時のパターンを探索
	if (subMatchFace(faces)){
		//指定された面と一致したならtrue
		return true;
	}

	//ラベル2,3,6が上面,背面、左面に来るように調節
	Dice::turn(DIR_X, 2);
	Dice::turn(DIR_Z, 3);

	//ラベル2,3,6を探索(現在の上面,背面、左面)が上面に来た時のパターンを探索
	if (subMatchFace(faces)){
		//指定された面と一致したならtrue
		return true;
	}

	return false;			//指定された面と一致しなかったのでfalse
}


//現在の上面,前面、右面が上面に来た時のパターンを探索
bool Dice::subMatchFace(int faces[FACE_SIZE]){
	for (unsigned int j = 0; j < FACE_SIZE / 2; ++j)
	{
		if (Dice::checkAllFace(faces)){
			return true;
		}
		//上面を固定した場合の、すべての可能性を探索
		//1方向に4回回せばサイコロは一周する
		for (unsigned int j = 0; j < 3; j++)
		{
			Dice::turn(DIR_Z);
			if (Dice::checkAllFace(faces)){
				return true;

			}
		}
		Dice::turn(DIR_X);
	}
	return false;
}

int main(){
	unsigned int n;
	Dice* dice;
	std::cin >> n;

	dice = new Dice[n];

	//dice1とdice2が一致するかチェック
	for (size_t i = 0; i < n-1; ++i)
	{
		for (size_t j = i+1; j < n; ++j)
		{
			if (dice[i].matchAllFace(dice[j].getAllPip()))
			{
				std::cout << "No" << std::endl;
				delete[] dice;
				return 0;
			}
		}
	}

	std::cout << "Yes" << std::endl;
	
	delete[] dice;

	return 0;
}


Measured memory_bytes: 3092