#include <bits/stdc++.h>
using namespace std;
const int maxn = 2550;
struct node {
  int a, b, c;
} e[maxn * maxn];
struct king {
  int next, to, dis;
} edge[maxn * 2];
int n, num = 0, cnt = 0, f[maxn], head[maxn], sq[maxn][maxn], dist[maxn][maxn];
bool legal() {
  for (int i = 1; i <= n; i++)
    for (int j = (i + 1); j <= n; j++)
      if (sq[i][j] != sq[j][i]) return false;
  return true;
}
bool cmp(node x, node y) { return x.c < y.c; }
void addedge(int u, int v, int w) {
  edge[++num].next = head[u];
  edge[num].to = v;
  edge[num].dis = w;
  head[u] = num;
}
int getfather(int a) {
  if (f[a] == a) return a;
  f[a] = getfather(f[a]);
  return f[a];
}
void kruskal() {
  sort(e + 1, e + 1 + cnt, cmp);
  for (int i = 1; i <= n; i++) f[i] = i;
  int tol = 0, now = 0;
  while (tol < (n - 1)) {
    now++;
    int fa = getfather(e[now].a), fb = getfather(e[now].b);
    if (fa != fb) {
      f[fa] = fb;
      tol++;
      addedge(e[now].a, e[now].b, e[now].c);
      addedge(e[now].b, e[now].a, e[now].c);
    }
  }
}
void dfs(int root, int now, int father) {
  for (int i = head[now]; i; i = edge[i].next)
    if (edge[i].to != father) {
      dist[root][edge[i].to] = max(dist[root][now], edge[i].dis);
      dfs(root, edge[i].to, now);
    }
}
bool judge() {
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
      if (dist[i][j] < sq[i][j]) return false;
  return true;
}
void work() {
  memset(dist, 0, sizeof(dist));
  for (int i = 1; i <= n; i++) {
    dist[i][i] = 0;
    dfs(i, i, i);
  }
  if (judge())
    printf("MAGIC\n");
  else
    printf("NOT MAGIC\n");
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++) {
      scanf("%d", &sq[i][j]);
      e[++cnt].a = i;
      e[cnt].b = j;
      e[cnt].c = sq[i][j];
    }
  if (!legal()) {
    printf("NOT MAGIC\n");
    return 0;
  }
  kruskal();
  work();
  return 0;
}
