//author: zekigurbuz
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<double> vd;
typedef vector<pii> vpii;
typedef queue<int> qi;
typedef map<string, int> msi;
#define RANGE_SUM 0
#define RANGE_MIN 1
#define RANGE_MAX 2
#define RANGE_XOR 3
#define RANGE_MUL 4
#define RANGE_OR  5
#define RANGE_AND 6
#define bit_ison(S, j) (S & (1 << j))
#define bit_setbit(S, j) (S |= (1 << j))
#define bit_clearbit(S, j) (S &= ~(1 << j))
#define bit_togglebit(S, j) (S ^= (1 << j))
#define bit_lowestbit(S) (S & (-S))
#define bit_setallon(S, n) (S = (1 << n) - 1)
#define bit_ispowertwo(S) (!(S & (S - 1))
#define bit_turnofflastbit(S) ((S) & (S - 1))
#define bit_turnonlastzero(S) ((S) | (S + 1))
#define int ll
#define double ld
#define M0D 1000000007
#define imin -(1e18)
#define imax 1e18
#define endl '\n'
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define forn(a,b) for(int a=0;a<b;++a)
#define rep(a,b,c) for(int a=b;a<c;++a)
const ld PI = 4*atan((ld)1);
vs split(string s){vs v;istringstream iss(s);do{string sub;iss>>sub;v.pb(sub);}while(iss);v.pop_back();return v;}
int gcd(int a,int b){return a==0?b:gcd(b%a,a);}
int lcm(int a,int b){return a*b/gcd(a,b);}
int p0wm(int n,int p,int m){if(p==0)return 1;if(p==1)return n%m;if(p%2==0){int t=p0wm(n,p/2,m);return t%m*t%m%m;}int t=p0wm(n,p/2,m);t=t%m*t%m%m;return t%m*n%m%m;}
int p0w(int n,int p){if(p==0)return 1;if(p==1)return n;if(p%2==0){int t=p0w(n,p/2);return t*t;}int t=p0w(n,p/2);return t*t*n;}
int m0d(int n,int m){return(m+(n%m))%m;}
int fact(int n){int a=1;for(int i=1;i<=n;++i)a*=i;return a;}
bool ip(int n){if(n<=1)return false;if(n==2)return true;for(int i=2;i*i<=n;++i)if(n%i==0)return false;return true;}
vb ps(int n){vector<bool> p;forn(i,n+1){p.pb(true);}p[0]=false;p[0]=p[1]=false;for(int i=2;i*i<=n;++i){if(p[i]){for(int j=i*i;j<=n;j+=i){p[j]=false;}}}return p;}
vi psp(int n){vector<bool>p=ps(n);vi a;forn(i,n+1)if(p[i])a.pb(i);return a;}
//variables: vi pset, vi size, int numsets. methods: constructor(int n), int find_set(int i) void unify(int i, int j) bool same_set(int i, int j)
struct dsu{vi pset;vi size;int numsets;dsu(int n){numsets=n;pset.resize(n);size.resize(n);forn(i,n)pset[i]=i;forn(i,n)size[i]=1;}int find_set(int i){return pset[i]==i?i:pset[i]=find_set(pset[i]);}void unify(int i,int j){int a=find_set(i),b=find_set(j);if(a==b)return;numsets--;if(size[a]<size[b]){pset[a]=b;size[b]+=size[a];}else{pset[b]=a;size[a]+=size[b];}}bool same_set(int i,int j){return find_set(i)==find_set(j);}int size_set(int i){return size[find_set(i)];}};
//variables: vi bit, int size. methods: constructor(int n), int sum(int a), int sum(int a, int b), void update(int k, int x)
struct fenwick{vi bit;int size;fenwick(int n){size=n;bit.resize(n+1,0);}int sum(int a){int s=0;while(a>=1){s+=bit[a];a-=a&-a;}return s;}int sum(int a,int b){return sum(b)-(a==1?0:sum(a-1));}void update(int k,int x){while(k<=size){bit[k]+=x;k+=k&-k;}}};
//variables: int code, int size, vi segment_tree. methods: constructor(int n, int type), void update(...), int query(...)
struct segtree{int code;int size;vi segment_tree;segtree(int n,int type){n=(int)(2*pow(2,floor(log2(n))+3));size=n;code=type;segment_tree.resize(n,0);}void update(int index,int value){update(1,0,size-1,index,value);}void update(int index,int left,int right,int i,int value){if(left==right)segment_tree[index]=value;else{int mid=(left+right)/2;if(i<=mid){update(2*index,left,mid,i,value);}else{update(2*index+1,mid+1,right,i,value);}switch(code){case RANGE_SUM:segment_tree[index]=segment_tree[2*index]+segment_tree[2*index+1];break;case RANGE_MIN:segment_tree[index]=min(segment_tree[2*index],segment_tree[2*index+1]);break;case RANGE_MAX:segment_tree[index]=max(segment_tree[2*index],segment_tree[2*index+1]);break;case RANGE_XOR:segment_tree[index]=segment_tree[2*index]^segment_tree[2*index+1];break;case RANGE_MUL:segment_tree[index]=segment_tree[2*index]*segment_tree[2*index+1];break;case RANGE_OR:segment_tree[index]=segment_tree[2*index]|segment_tree[2*index+1];break;case RANGE_AND:segment_tree[index]=segment_tree[2*index]&segment_tree[2*index+1];break;}}}int query(int left,int right){return query(1,0,size-1,left,right);}int query(int index,int left,int right,int lhs,int rhs){if(left>=lhs&&right<=rhs){return segment_tree[index];}else{int ret=0;switch(code){case RANGE_SUM:ret=0;break;case RANGE_MIN:ret=imax;break;case RANGE_MAX:ret=imin;break;case RANGE_XOR:ret=0;break;case RANGE_MUL:ret=1;break;case RANGE_OR:ret=0;break;case RANGE_AND:ret=9223372036854775807;break;}int mid=(left+right)/2;if(mid>=lhs){switch(code){case RANGE_SUM:ret+=query(2*index,left,mid,lhs,rhs);break;case RANGE_MIN:ret=min(ret,query(2*index,left,mid,lhs,rhs));break;case RANGE_MAX:ret=max(ret,query(2*index,left,mid,lhs,rhs));break;case RANGE_XOR:ret^=query(2*index,left,mid,lhs,rhs);break;case RANGE_MUL:ret*=query(2*index,left,mid,lhs,rhs);break;case RANGE_OR:ret|=query(2*index,left,mid,lhs,rhs);break;case RANGE_AND:ret&=query(2*index,left,mid,lhs,rhs);break;}}if(mid+1<=rhs){switch(code){case RANGE_SUM:ret+=query(2*index+1,mid+1,right,lhs,rhs);break;case RANGE_MIN:ret=min(ret,query(2*index+1,mid+1,right,lhs,rhs));break;case RANGE_MAX:ret=max(ret,query(2*index+1,mid+1,right,lhs,rhs));break;case RANGE_XOR:ret^=query(2*index+1,mid+1,right,lhs,rhs);break;case RANGE_MUL:ret*=query(2*index+1,mid+1,right,lhs,rhs);break;case RANGE_OR:ret|=query(2*index+1,mid+1,right,lhs,rhs);break;case RANGE_AND:ret&=query(2*index+1,mid+1,right,lhs,rhs);break;}}return ret;}}};

signed main() {
	ios_base::sync_with_stdio(0);cin.tie(0);
	int n, d;
	cin >> n >> d;
	int a[n][d];
	forn(i, n) forn(j, d) cin >> a[i][j];
	int count = 0;
	forn(i, n) {
		for (int j = i + 1; j < n; j++) {
			double dist = 0;
			forn(k, d) {
				dist += pow(a[i][k] - a[j][k], 2);
			}
			dist = sqrt(dist);
			if (abs(dist - (int) dist) < 1e-6) ++count;
		}
	}
	cout << count << endl;
	return 0;
}
/* Think about this stuff:
   - printing: double -> int || printf
   - use for loop instead of memset
   - check bounds & edge cases
   - just implement something
   - find reason of tle
*/



Measured memory_bytes: 256