import std.stdio, std.conv, std.string, std.bigint;
import std.math, std.random, std.datetime;
import std.array, std.range, std.algorithm, std.container, std.format;
string read(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }

/*

----------------------------------------

xs[m]は、

mの立っているビットの個数をkとするとき、
mのビットが立っているところにいるk人のと、
0番からk - 1番までの男との間で成立するマッチングの個数

を表すとする

xs[0] = 1

xs[m]は、累乗を用いて
m = or(i; 0 .. k) m[i]
とかかれるとき
m = sum xs[m[i] xor m]
ただしこの和は、k - 1番の男とm[i]の表す女がマッチする場合にわたる和


求めるものは
xs[1<<n - 1]

----------------------------------------

xs[0] = 1


xs[m]は、(i; 0 .. n) に対して、以下の和

mのビットの立っている個数をkとする

1<<i & m == 0 ならば 0

1<<i & m > 0 であって、

	as[i][k - 1] == 0 ならば 0
	
	as[i][k - 1] > 0 ならば xs[m ^ (1<<i)]

*/

const long mod = 1_000_000_007;

void main(){
 int n = read.to!int;
 
 int[][] as;
 foreach(i; 0 .. n) as ~= readln.chomp.split.map!(to!int).array;
 
 long[] xs = [1];
 foreach(m; 1 .. 1<<n){
	 long k = 0;
	 foreach(i; 0 .. n) if(m & (1<<i)) k += 1;
	 
	 long x = 0;
	 foreach(i; 0 .. n){
		 debug writeln("m:", m, " k:", k, " i:", i, " xs:", xs);
		 if(m & (1<<i)) if(as[i][k - 1] > 0){
			 x += xs[m ^ (1<<i)];
			 x %= mod;
		 }
	 }
	 xs ~= x;
 }
 
 xs[(1<<n) - 1].writeln;
 
}
