#include <iostream>
#include <string>
const int SURFACE_NUM = 6;
enum Direction{TOP, SOUTH, EAST, WEST, NORTH, BOTTOM};

class Dice{
public:
    void roll(char op);
    int top(){
        return label_value[label_dir[TOP]];
    }
    Dice(){}
    Dice(int label_value[SURFACE_NUM]);
    void resetDirection();
    int getValue(Direction dir){
        return label_value[label_dir[dir]];
    }
    bool matchAxis(Dice otherdice);
private:
    Direction label_dir[SURFACE_NUM];//lavel_dir[dir] は 方角dirの面p
    int label_value[SURFACE_NUM];//label_value[p] は 面pの数値
};

Dice::Dice(int lv[SURFACE_NUM]){
    for(int i = 0; i < SURFACE_NUM; i++) Dice::label_value[i] = lv[i];
    resetDirection();
}

void Dice::roll(char op){
    Direction tmp;
    switch(op){
    case 'E':
        tmp = label_dir[BOTTOM];
        label_dir[BOTTOM] = label_dir[EAST];
        label_dir[EAST] = label_dir[TOP];
        label_dir[TOP] = label_dir[WEST];
        label_dir[WEST] = tmp;
        break;
    case 'N':
        tmp = label_dir[NORTH];
        label_dir[NORTH] = label_dir[TOP];
        label_dir[TOP] = label_dir[SOUTH];
        label_dir[SOUTH] = label_dir[BOTTOM];
        label_dir[BOTTOM] = tmp;
        break;
    case 'S':
        tmp = label_dir[BOTTOM];
        label_dir[BOTTOM] = label_dir[SOUTH];
        label_dir[SOUTH] = label_dir[TOP];
        label_dir[TOP] = label_dir[NORTH];
        label_dir[NORTH] = tmp;
        break;
    case 'W':
        tmp = label_dir[EAST];
        label_dir[EAST] = label_dir[BOTTOM];
        label_dir[BOTTOM] = label_dir[WEST];
        label_dir[WEST] = label_dir[TOP];
        label_dir[TOP] = tmp;
        break;
    }
}

void Dice::resetDirection(){
    for(int i = 0; i < SURFACE_NUM; i++) Dice::label_dir[i] = static_cast<Direction>(i);
    /*
    label_dir[0] = label_dir[TOP] = 0;//面0
    label_dir[1] = label_dir[SOUTH] = 1;//面1
    ...
    label_dir[5] = label_dir[BOTTOM] = 5;//面5
    */
}

bool Dice::matchAxis(Dice otherdice){
    //自身のNORTHに書かれた数値を他方のサイコロから探す
    Direction otherDir;//他方のサイコロで、自身のNORTHの数値が書かれた面
    bool result = false;
    for(int i = 0; i < SURFACE_NUM; i++){
        if(getValue(NORTH) == otherdice.getValue(static_cast<Direction>(i))){
            otherDir = static_cast<Direction>(i);
            result = true;
        }
    }

    if(!result) return false;//自身のTOPに書かれた数値が他方のサイコロに書かれていない場合は終了

    //他方のサイコロのNORTHに書かれた数値が他方のサイコロでもNORTHに来るように誘導
    if(otherDir == TOP){
        otherdice.roll('N');
    }else if(otherDir == EAST){
        otherdice.roll('W');
        otherdice.roll('N');
    }else if(otherDir == WEST){
        otherdice.roll('E');
        otherdice.roll('N');
    }else if(otherDir == SOUTH){
        otherdice.roll('N');
        otherdice.roll('N');
    }else if(otherDir == BOTTOM){
        otherdice.roll('S');
    }
    
    //2つのサイコロのSOUTHが一致するかチェック
    if(getValue(SOUTH) != otherdice.getValue(SOUTH)) return false;

    //残りの面をチェック
    result = false;
    for(int i = 0; i < 4; i++){
        if(getValue(TOP) == otherdice.getValue(TOP)){
            result = true;
            break;
        }else{
            otherdice.roll('E');
        }
    }

    if(result){
        result = (getValue(EAST) == otherdice.getValue(EAST)) &&
        (getValue(BOTTOM) == otherdice.getValue(BOTTOM)) &&
        (getValue(WEST) == otherdice.getValue(WEST));
    }

    return result;
}

int main(){
    using namespace std;
    int dice_value[100][SURFACE_NUM];
    int n;
    cin >> n;
    for(int i = 0; i < n; i++){
        for(int j = 0; j < SURFACE_NUM; j++) cin >> dice_value[i][j];
    }
    
    Dice ds[100];
    for(int i = 0; i < n; i++) ds[i] = Dice(dice_value[i]);

    string res = "Yes";
    for(int i = 0; i < n; i++){
        for(int j = i+1; j < n; j++){
            if(ds[i].matchAxis(ds[j])) res = "No";
        }
    }

    cout << res << endl;

    return 0;
}


Measured memory_bytes: 3208