import java.util.Scanner;
class Main{


	static char[][] map;

	static long[][] c;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		int d = sc.nextInt();
		
		int[][] data = new int[n][d];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		}
		System.out.print(ans);
		
		

		
	}
	
	static boolean judge(int num){
		
		for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		}
		
		return false;
		
		
	}


	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}



class Pair implements Comparable{
	int from;
	int end;
	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return   end- otherpair.end;
	}







	static int find(int index,int current,int[] students,int ans,int[][] memo){
		if(current == index){
			return 1;
		}

		if(memo[current][index] != 0){
			return memo[current][index];
		}

		memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1;

		return memo[current][index];
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}



 import java.util.Scanner; Scanner java.util class Main{


	static char[][] map;

	static long[][] c;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		int d = sc.nextInt();
		
		int[][] data = new int[n][d];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		}
		System.out.print(ans);
		
		

		
	}
	
	static boolean judge(int num){
		
		for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		}
		
		return false;
		
		
	}


	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




} Main static char[][] map; map static long[][] c; c public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		int d = sc.nextInt();
		
		int[][] data = new int[n][d];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		}
		System.out.print(ans);
		
		

		
	} main {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		int d = sc.nextInt();
		
		int[][] data = new int[n][d];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		}
		System.out.print(ans);
		
		

		
	} Scanner sc = new Scanner(System.in); sc new Scanner(System.in) int n = sc.nextInt(); n sc.nextInt() sc.nextInt sc int d = sc.nextInt(); d sc.nextInt() sc.nextInt sc int[][] data = new int[n][d]; data new int[n][d] n d for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		} int i = 0; int i = 0; i 0 i < n i n i++ i++ i {
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		} {
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		} for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			} int j = 0; int j = 0; j 0 j < d j d j++ j++ j {
				data[i][j] = sc.nextInt();
			} {
				data[i][j] = sc.nextInt();
			} data[i][j] = sc.nextInt() data[i][j] data[i] data i j sc.nextInt() sc.nextInt sc int ans = 0; ans 0 for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		} int i = 0; int i = 0; i 0 i < n i n i++ i++ i {
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		} {
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		} for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			} int j = i + 1; int j = i + 1; j i + 1 i 1 j < n j n j++ j++ j {
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			} {
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			} int calc = 0; calc 0 for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				} int k = 0; int k = 0; k 0 k < d k d k++ k++ k {
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				} {
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				} calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]) calc Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]) Math.abs(data[i][k] - data[j][k]) Math.abs Math data[i][k] - data[j][k] data[i][k] data[i] data i k data[j][k] data[j] data j k Math.abs(data[i][k] - data[j][k]) Math.abs Math data[i][k] - data[j][k] data[i][k] data[i] data i k data[j][k] data[j] data j k if(judge(calc)){
					ans++;
				} judge(calc) judge calc {
					ans++;
				} ans++ ans System.out.print(ans) System.out.print System.out System System.out ans String[] args args static boolean judge(int num){
		
		for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		}
		
		return false;
		
		
	} judge {
		
		for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		}
		
		return false;
		
		
	} for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		} int i = 1; int i = 1; i 1 i*i <= num i*i i i num i++ i++ i {
			if(i*i == num){
				return true;
			}
		} {
			if(i*i == num){
				return true;
			}
		} if(i*i == num){
				return true;
			} i*i == num i*i i i num {
				return true;
			} return true; true return false; false int num num static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b int a a int b b static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b long a a long b b static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	} lcm {
		long g = gcd(a,b);
		return a/g*b;
	} long g = gcd(a,b); g gcd(a,b) gcd a b return a/g*b; a/g*b a/g a g b long a a long b b class Pair implements Comparable{
	int from;
	int end;
	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return   end- otherpair.end;
	}







	static int find(int index,int current,int[] students,int ans,int[][] memo){
		if(current == index){
			return 1;
		}

		if(memo[current][index] != 0){
			return memo[current][index];
		}

		memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1;

		return memo[current][index];
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




} Pair int from; from int end; end @Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return   end- otherpair.end;
	} compareTo {
		Pair otherpair = (Pair)other;

		return   end- otherpair.end;
	} Pair otherpair = (Pair)other; otherpair (Pair)other return   end- otherpair.end; end- otherpair.end end otherpair.end otherpair otherpair.end Object other other static int find(int index,int current,int[] students,int ans,int[][] memo){
		if(current == index){
			return 1;
		}

		if(memo[current][index] != 0){
			return memo[current][index];
		}

		memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1;

		return memo[current][index];
	} find {
		if(current == index){
			return 1;
		}

		if(memo[current][index] != 0){
			return memo[current][index];
		}

		memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1;

		return memo[current][index];
	} if(current == index){
			return 1;
		} current == index current index {
			return 1;
		} return 1; 1 if(memo[current][index] != 0){
			return memo[current][index];
		} memo[current][index] != 0 memo[current][index] memo[current] memo current index 0 {
			return memo[current][index];
		} return memo[current][index]; memo[current][index] memo[current] memo current index memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1 memo[current][index] memo[current] memo current index find(index, students[current]-1, students, ans+1, memo)+1 find(index, students[current]-1, students, ans+1, memo) find index students[current]-1 students[current] students current 1 students ans+1 ans 1 memo 1 return memo[current][index]; memo[current][index] memo[current] memo current index int index index int current current int[] students students int ans ans int[][] memo memo static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b int a a int b b static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b long a a long b b static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	} lcm {
		long g = gcd(a,b);
		return a/g*b;
	} long g = gcd(a,b); g gcd(a,b) gcd a b return a/g*b; a/g*b a/g a g b long a a long b b Comparable
import java.util.Scanner;
class Main{


	static char[][] map;

	static long[][] c;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		int d = sc.nextInt();
		
		int[][] data = new int[n][d];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < d;j++){
				data[i][j] = sc.nextInt();
			}
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			for(int j = i + 1;j < n;j++){
				int calc = 0;
				for(int k = 0;k < d;k++){
					calc += Math.abs(data[i][k] - data[j][k])*Math.abs(data[i][k] - data[j][k]);
				}
				if(judge(calc)){
					ans++;
				}
			}
		}
		System.out.print(ans);
		
		

		
	}
	
	static boolean judge(int num){
		
		for(int i = 1;i*i <= num;i++){
			if(i*i == num){
				return true;
			}
		}
		
		return false;
		
		
	}


	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}



class Pair implements Comparable{
	int from;
	int end;
	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return   end- otherpair.end;
	}







	static int find(int index,int current,int[] students,int ans,int[][] memo){
		if(current == index){
			return 1;
		}

		if(memo[current][index] != 0){
			return memo[current][index];
		}

		memo[current][index] = find(index, students[current]-1, students, ans+1, memo)+1;

		return memo[current][index];
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}




