#include using namespace std; template class y_combinator { F f; public: y_combinator(F&& f) : f(std::forward(f)) {} template auto operator()(Args&&... args) const { return f(*this, std::forward(args)...); } }; using ll = long long; using ld = long double; template > using prique = std::priority_queue, U>; template T floor(T a, T b) noexcept { return a / b - (a % b && (a ^ b) < 0); } template T ceil(T a, T b) noexcept { return floor(a + b - 1, b); } template bool chmin(T& x, const T& y) noexcept { return (x > y ? x = y, true : false); } template bool chmax(T& x, const T& y) noexcept { return (x < y ? x = y, true : false); } #define overload4(a, b, c, d, e, ...) e #define rep1(a) for (long long _i = 0; _i < (a); _i++) #define rep2(i, a) for (long long i = 0; i < (a); i++) #define rep3(i, a, b) for (long long i = (a); i < (b); i++) #define rep4(i, a, b, c) for (long long i = (a); i < (b); i += (c)) #define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__) #define rrep(i, a, b, c) for (long long i = (a); i > (b); i += (c)) #define all(x) std::begin(x), std::end(x) #define rall(x) std::rbegin(x), std::rend(x) #define pb push_back #ifndef LOCAL #define debug(...) #endif #include namespace internal { constexpr long long safe_mod(long long x, long long m) { x %= m; if (x < 0) x += m; return x; } constexpr long long pow_mod_constexpr(long long x, long long n, int m_) { if (m_ == 1) return 0; unsigned int m = static_cast(m_); unsigned long long r = 1, y = safe_mod(x, m); while (n) { if (n & 1) { r = (r * y) % m; } y = (y * y) % m; n >>= 1; } return r; } constexpr bool is_prime_constexpr(int n) { if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; long long t = n - 1; while (t % 2 == 0) t /= 2; constexpr long long base[3] = {2, 7, 61}; for (long long a : base) { long long d = t; long long v = pow_mod_constexpr(a, t, n); if (v == 1) continue; while (d != n - 1 && v != n - 1) { v = v * v % n; d <<= 1; } if (v != n - 1) return false; } return true; } template constexpr bool is_prime = is_prime_constexpr(n); constexpr std::pair inv_gcd(long long a, long long b) { a = safe_mod(a, b); if (a == 0) return {b, 0}; long long s = b, t = a; long long m0 = 0, m1 = 1; while (t) { long long u = s / t; s -= t * u; m0 -= m1 * u; auto tmp = s; s = t; t = tmp; tmp = m0; m0 = m1; m1 = tmp; } if (m0 < 0) m0 += b / s; return {s, m0}; } constexpr long long inv_mod(long long x, long long m) { assert(1 <= m); auto z = inv_gcd(x, m); assert(z.first == 1); return z.second; } constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; i <= x / i; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) x /= i; } } if (x > 1) divs[cnt++] = x; for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template constexpr int primitive_root = primitive_root_constexpr(m); unsigned long long floor_sum_unsigned(unsigned long long n, unsigned long long m, unsigned long long a, unsigned long long b) { unsigned long long ans = 0; while (true) { if (a >= m) { ans += n * (n - 1) / 2 * (a / m); a %= m; } if (b >= m) { ans += n * (b / m); b %= m; } unsigned long long y_max = a * n + b; if (y_max < m) break; n = (unsigned long long)(y_max / m); b = (unsigned long long)(y_max % m); std::swap(m, a); } return ans; } } // namespace internal template class StaticModint { unsigned value; using mint = StaticModint; static constexpr bool is_prime = internal::is_prime; static constexpr unsigned umod() { return m; } public: static constexpr unsigned mod() { return m; } static mint raw(int v) { mint x; x.value = v; return x; } StaticModint() : value(0) {} template , int> = false> StaticModint(T v) { value = static_cast(internal::safe_mod(v, m)); } int val() const { return value; } mint& operator++() { value = (value + 1 == umod() ? 0 : value + 1); return *this; } mint& operator--() { value = (value == 0 ? umod() - 1 : value - 1); return *this; } mint operator++(int) { mint res = *this; ++*this; return res; } mint operator--(int) { mint res = *this; --*this; return res; } mint& operator+=(const mint& rhs) { value += rhs.value; if (value >= umod()) value -= umod(); return *this; } mint& operator-=(const mint& rhs) { if (value < rhs.value) value += umod(); value -= rhs.value; return *this; } mint& operator*=(const mint& rhs) { unsigned long long z = value; z *= rhs.value; value = static_cast(z % umod()); return *this; } mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } mint operator+() const { return *this; } mint operator-() const { return mint() - *this; } mint pow(long long n) const { assert(0 <= n); mint x = *this, r = 1; for (; n; n >>= 1, x *= x) if (n & 1) r *= x; return r; } mint inv() const { return (is_prime ? pow(m - 2) : internal::inv_mod(value, m)); } friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint& lhs, const mint& rhs) { return lhs.value == rhs.value; } friend bool operator!=(const mint& lhs, const mint& rhs) { return lhs.value != rhs.value; } template void print(Pr& p) const { p << value; } template void scan(Sc& s) { s >> value; } }; using modint998 = StaticModint<998244353>; using modint107 = StaticModint<1000000007>; template struct combination { private: std::vector _fact, _ifac; void expand(size_t N) { const size_t a = _fact.size(); if(a > N) return; _fact.resize(N + 1); for(size_t i = a; i <= N; i++) _fact[i] = _fact[i - 1] * i; _ifac.resize(N + 1); _ifac[N] = Mint{1} / _fact[N]; for(size_t i = N; i > a; i--) _ifac[i - 1] = _ifac[i] * i; } public: combination(size_t N = 0) : _fact(1, 1), _ifac(1, 1) { expand(N); } Mint fact(size_t x) { expand(x); return _fact[x]; } Mint invfact(size_t x) { expand(x); return _ifac[x]; } Mint perm(size_t N, size_t K) { if(N < K) return Mint{0}; expand(N); return _fact[N] * _ifac[N - K]; } Mint comb(size_t N, size_t K) { if(N < K) return Mint{0}; expand(N); return _fact[N] * _ifac[K] * _ifac[N - K]; } Mint homo(size_t N, size_t K) { if(N == 0) return K == 0 ? Mint{1} : Mint{0}; return comb(N - 1 + K, K); } }; using mint = modint107; combination C; int N, M; int S[1010][1010]; mint naive() { mint ans = 0; rep(i, N) rep(j, M) { ans += C.comb(i + j + S[i][j] - 1, S[i][j] - 1) * C.comb(i + j, j); } rep(i, N - 1) rep(j, M) { rep(k, S[i + 1][j], S[i][j]) ans += C.comb(k + i + j, k) * C.comb(i + j, j); } rep(i, N) rep(j, M - 1) { rep(k, S[i][j + 1], S[i][j]) ans += C.comb(k + i + j, k) * C.comb(i + j, j); } rep(j, M) { int i = N - 1; rep(k, S[i][j]) ans += C.comb(i + j + k, k) * C.comb(i + j, j); } rep(i, N) { int j = M - 1; rep(k, S[i][j]) ans += C.comb(i + j + k, k) * C.comb(i + j, j); } cout << ans.val() << "\n"; return ans; } int main() { cin >> N >> M; rep(i, N) rep(j, M) cin >> S[i][j]; mint ans = 0; rep(i, N) rep(j, M) { ans += C.comb(i + j + S[i][j] - 1, S[i][j] - 1) * C.comb(i + j, j); } auto f = [&](int i, int j, int lo, int hi) -> mint { // [lo, hi) // rep(k, lo, hi) ans += C.comb(i + j + k, k) * C.comb(i + j, j); int u = i + j; mint sum = C.comb(u + 1 + hi - 1, hi - 1) - C.comb(u + 1 + lo - 1, lo - 1); return sum * C.comb(i + j, j); }; rep(i, N - 1) rep(j, M) { ans += f(i, j, S[i + 1][j], S[i][j]); } rep(i, N) rep(j, M - 1) { ans += f(i, j, S[i][j + 1], S[i][j]); } rep(j, M) { int i = N - 1; ans += f(i, j, 0, S[i][j]); } rep(i, N) { int j = M - 1; ans += f(i, j, 0, S[i][j]); } cout << ans.val() << "\n"; }