#include <stdio.h>

/*構造体*/
typedef struct dice
{
	int Upper;
	int South;
	int East;
	int West;
	int North;
	int Under;
} Dice;

/*関数*/
//構造体を初期化する
Dice InitDice(void);
//さいころの構造体に値を入力する
Dice InputDiceNum(void);
//要素を入れ替える
Dice RotateDice(Dice dice);
Dice ChangeNum_East(Dice dice);
Dice ChangeNum_South(Dice dice);
//さいころ1とさいころ2を比較する
int StructCmp(Dice dice1, Dice dice2);
//さいころを動かす
int MoveDice(Dice dice1, Dice dice2, int EorS);

/*宣言*/
#define diceMax 100
#define diceFace 6

int main(void)
{
	Dice dice[diceMax];	//さいころの配列
	int n;				//さいころの数
	int result = 0;		//結果
	int i;
	int j;
	
	//さいころの数を入力する
	scanf("%d", &n);

	//さいころの個数分値を入力する
	for (i = 0; i < n; i++)
	{
		dice[i] = InputDiceNum();
	}

	//さいころを比較していく
	for (i = 0; i < n - 1; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			//さいころをE方向に動かして、2つのさいころを比較する
			if (MoveDice(dice[i], dice[j], 0) > 0)
			{
				result += 1;
			}
			//さいころをS方向に動かして、2つのさいころを比較する
			else if (MoveDice(dice[i], dice[j], 1) > 0)
			{
				result += 1;
			}
			else
			{
				//何もしない
			}
		}
	}

	if (result > 0)
	{
		printf("No\n");
	}
	else
	{
		printf("Yes\n");
	}

	return 0;
}

//構造体を初期化する
Dice InitDice(void)
{
	Dice di;

	di.Upper = 0;
	di.South = 0;
	di.East = 0;
	di.West = 0;
	di.North = 0;
	di.Under = 0;

	return di;
}

//さいころの構造体に値を入力する
Dice InputDiceNum(void)
{
	Dice di = InitDice();

	scanf("%d%d%d%d%d%d", &di.Upper, &di.South, &di.East,
		&di.West, &di.North, &di.Under);

	return di;
}

//反時計回りにい1面ずつ回転する
Dice RotateDice(Dice dice)
{
	Dice di = InitDice();

	di.Upper = dice.Upper;
	di.South = dice.West;
	di.East = dice.South;
	di.West = dice.North;
	di.North = dice.East;
	di.Under = dice.Under;

	return di;
}

//E方向に転がす
Dice ChangeNum_East(Dice dice)
{
	Dice di = InitDice();

	di.Upper = dice.West;
	di.South = dice.South;
	di.East = dice.Upper;
	di.West = dice.Under;
	di.North = dice.North;
	di.Under = dice.East;

	return di;
}

//S方向に転がす
Dice ChangeNum_South(Dice dice)
{
	Dice di = InitDice();

	di.Upper = dice.North;
	di.South = dice.Upper;
	di.East = dice.East;
	di.West = dice.West;
	di.North = dice.Under;
	di.Under = dice.South;

	return di;
}

//さいころ1とさいころ2を比較する
int StructCmp(Dice dice1, Dice dice2)
{
	//printf("dice1.Upper : %d || dice2.Upper : %d\n", dice1.Upper, dice2.Upper);
	//printf("dice1.South : %d || dice2.South : %d\n", dice1.South, dice2.South);
	//printf("dice1.East  : %d || dice2.East  : %d\n", dice1.East, dice2.East);
	//printf("dice1.West  : %d || dice2.West  : %d\n", dice1.West, dice2.West);
	//printf("dice1.North : %d |i dice2.North : %d\n", dice1.North, dice2.North);
	//printf("dice1.Under : %d || dice2.Under : %d\n\n", dice1.Under, dice2.Under);

	if (dice1.Upper == dice2.Upper)
	{
		if (dice1.South == dice2.South)
		{
			if (dice1.East == dice2.East)
			{
				if (dice1.West == dice2.West)
				{
					if (dice1.North == dice2.North)
					{
						if (dice1.Under == dice2.Under)
						{
							return 1;
						}
						else
						{
							return 0;
						}
					}
					else
					{
						return 0;
					}
				}
				else
				{
					return 0;
				}
			}
			else
			{
				return 0;
			}
		}
		else
		{
			return 0;
		}
	}
	else
	{
		return 0;
	}
}

//さいころを動かす
int MoveDice(Dice dice1, Dice dice2, int EorS)
{
	int operation[] = { 30, 20, 30, 20, 30, 20, 30, 20,
					10, 30, 20, 30, 20, 30, 20, 30, 20,
					10, 30, 20, 30, 20, 30, 20, 30, 20,
					10, 30, 20, 30, 20, 30, 20, 30, 20,
					40 };	//命令の行列
	int ope = 0;

	while (1)
	{
		switch (operation[ope])
		{
			//E方向へ1回動かす
		case 10:
			if (EorS == 0)
			{
				dice2 = ChangeNum_East(dice2);
			}
			else
			{
				dice2 = ChangeNum_South(dice2);
			}
			++ope;
			break;
			
			//その場で3回回転する
		case 20:
			dice2 = RotateDice(dice2);
			++ope;
			break;

			//2つのさいころを比較する
		case 30:
			if (StructCmp(dice1, dice2) == 1)
			{
				return 1;
			}
			else
			{
				++ope;
				break;
			}

		default:
			return 0;
		}
			
	}
}



Measured memory_bytes: 2148