#include <bits/stdc++.h>
#pragma GCC optimize( \
    "O3,Ofast,unroll-loops,no-stack-protector,fast-math,inline")
#pragma GCC target( \
    "sse,sse2,sse3,ssse3,sse4,popcnt,lzcnt,mmx,abm,avx,avx2,tune=native")
const int inf = INT_MAX;
const int mod = (int)1e9 + 7;
using namespace std;
template <class T, class T2>
void smin(T& a, T2 val) {
  if (a > val) a = val;
}
template <class T, class T2>
void smax(T& a, T2 val) {
  if (a < val) a = val;
}
const int N = 5 * (int)1e5 + 10;
int n;
vector<vector<int>> defd;
vector<vector<int>> v[N];
vector<vector<int>> match;
vector<int> min_ancestor;
vector<int> curr;
void dfs(int s, int p = -1, int sum = 0) {
  curr[s] = sum;
  for (auto i : v[s]) {
    if (i[0] != p) {
      dfs(i[0], s, sum + i[1]);
    }
  }
}
struct UnionFind {
  vector<int> parent, size;
  UnionFind(int n) {
    parent.resize(n + 1);
    size.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
      parent[i] = i;
      size[i] = 1;
    }
  }
  int find(int x) {
    while (x != parent[x]) {
      parent[x] = parent[parent[x]];
      x = parent[x];
    }
    return x;
  }
  bool unite(int x, int y) {
    x = find(x), y = find(y);
    if (x == y) return false;
    if (size[x] < size[y]) swap(x, y);
    size[x] += size[y];
    parent[y] = x;
    return true;
  }
  int getSize(int x) {
    x = find(x);
    return size[x];
  }
};
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  cin >> n;
  min_ancestor.resize(n, inf);
  defd.resize(n);
  for (int i = 0; i < n; ++i) {
    defd[i].resize(n);
    for (int j = 0; j < n; ++j) {
      cin >> defd[i][j];
      if (i != j) {
        if (defd[i][j] <= 0) {
          cout << "NO";
          exit(0);
        }
      } else {
        if (defd[i][j] != 0) {
          cout << "NO";
          exit(0);
        }
      }
    }
  }
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      if (defd[i][j] != defd[j][i]) {
        cout << "NO";
        exit(0);
      }
    }
  }
  UnionFind S(n);
  vector<array<int, 3>> edges;
  for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
      edges.push_back({defd[i][j], i, j});
    }
  }
  sort(edges.begin(), edges.end());
  for (auto& it : edges) {
    if (S.unite(it[1], it[2])) {
      v[it[1]].push_back({it[2], it[0]});
      v[it[2]].push_back({it[1], it[0]});
    }
  }
  for (int i = 0; i < n; ++i) {
    curr.assign(n, inf);
    dfs(i);
    match.push_back(curr);
  }
  if (match != defd) {
    cout << "NO";
  } else {
    cout << "YES";
  }
  return 0;
}
