#include <bits/stdc++.h>

using namespace std;
inline void prep ()
{
  cin.tie (0);
  cin.sync_with_stdio (0);
};
//printf("%.12lf\n",mid);
// __builtin_popcount(int) count 1's in binary
// get decimal pert of number
/*
double intpart;
double thiss = modf((double)(n*m)/(double)k, &intpart);
*/
// round = (int)(num+.5)
int mod = 1000000007;

long long mymod(long long num){
  if (num< 0 && !(abs(num)%mod == 0)){
    if (mod == 1){
      return 0;
    }
    return mod-abs(num)%mod;
  }else{
    return num%mod;
  }
}

double eps = .000000001;

// fill w/ doubles fill_n(valss, 51, 20000000000LL);

int main ()
{
  prep ();
  int n, d;
  cin >> n >> d;
  int cnt = 0;
  vector<vector<int> > these;
  for (int i=0; i<n; i++){
      vector<int> temp;
      for (int j=0; j<d; j++){
          int num;
          cin >> num;
          temp.push_back(num);
      }
      these.push_back(temp);
  }
  set<int> squares;
  for (int i=0; i<200; i++){
      squares.insert(i*i);
  }
  for (int i=0; i<n; i++){
      for (int j=i+1; j<n; j++){
          int res = 0;
          for (int k=0; k<d; k++){
              res += abs(these[i][k]-these[j][k])*abs(these[i][k]-these[j][k]);
          }
          
          if (squares.count(res)){
              cnt++;
          }
      }
  }
  cout << cnt;
  return 0;
}

// in dp problems think: up until here, intervals, or "what if there's 1, 2, 3..."
// in math problems write out equations
// also in math problems to change multiplication/division to addition/subtraction use logs, add/subtract something to make the multiplication easier (like if it's 3*f(x)+2, change it to 3*(f(x)+1)-1)
// if checked the logic check for bugs (like sorting wrong way or not putting a break in a loop)
// if n is 10^7 try brute force if the operations are simple
// if can't do dp do brute force/greedy
// to save time don't copy maps/vectors into variables if it already exists
// if wrong on decimal problem, check if program rounds or if you can round to a certain amt of decimals
// if decimals too, if can subtract instead of divide
// in recursion looking math problems look at things from the point of view of both sides (the start and the end sections of the recursion)
// think about how many possible answers there are to the problem
// try to set the answer to the problem and see if it's possible (like w/ binary search)
// if it makes it easier use +1 indexing
// think twice when writing things down that you're going to use later
// for conversions think if you can compute them w/ only one conversion 
// if the problem involves two things moving at the same time, see if you can generalise it to just one thing moving (590/B) (1117/C)
// if nt think primes
// see if you can do a pattern of steps to achieve something (1148/C) (1119/C)
// if sub-interval requirements, try to reduce problem into prefix array problem (pairwise numbers) (1174/D)
// think from the end of the problem (if this is the result, what is an attribute of it?)
// if repeating action, if good for debugging use function
// read problems twice, think about problem, even if have solution keep thinking about a more optimal one
// for uva see constraints, check if have to use getline (there's spaces in input)
// if permutations, see if you can just iterate over numbers (like if it's a perm of 10 numbers)
// for geom check if it could be on inside/outside if intersections
// stop just assuming things (like on the problem where you just thought that there couldn't be 3 2's because 3 is odd)
// obviously, check problems solved by users occasionally to see if you should switch problems
// if # of sols are small precalculate
// if question is asking to find an optimal place, don't focus on finding the place, use what other things they give you to precalculate it (593/B) (Uva rat attack)
// if a constraint looks purposely small try to use it
// if can, change vector<bool> to bitset
// if brute force, try meet in middle
// if using dfs and using visited, after visit node, mark as not visited and keep vis global
// if it's one of those creative problems, try to make the most/least possible, try to use very small example to prove things
// what are we forced to do because of the problem's constraints? (like if it's graph and 1s time lim, is probably only 1 traverse of dfs and not n)
// if greedy, look at an observation like "they have to be as far out as they can" or "it's optimal to always put them here" for example
// if you think about binary search, don't just drop the idea quickly
// if it's a minutes/seconds question, convert everything to seconds
// try to avoid decimals
// for bisection don't use a last good variable
// if it's one of those problems where there's a lot of cases, go through the code again and see if there's a scenario you didn't think of
// if trying to maximize something, before categorizing/matching positives/negatives or evens/odds try only sorting
// when trying to find bugs, don't try input, look at code
// try not to categorize things (ex: if it's in front of this, it's this, and if it's in back of this, it's that)
// for simulation problems, to make it easier, see if you can use set to see if something's there
// if interval prob, also think about brute forcing intervals instead of prefix array
// avoid division at all costs
// max 2d sum => n^3 = iterate through columns + greedy
// if trying to find optimal way to move something, try looking at things you aren't moving
// initializing list is linear
// brute force subsequence => queue
// if dp + order doesn't matter + limit on different kinds, put the different kinds in separate bins
// if dp, work through recursive and check for logic flaws and places where something could surpass array size
// for ceil, be careful if you think it's an int but it has a little decimal left
// write neater, don't do long lines
// with "coin change" dp try to avoid ind (it creates more edge cases). plus, don't assume you have an infinite amt of everything
// try reaching the end goal and then check the requirement (last resort) (like if it says to do # of things at a time to reach the goal) (AtcoderBC E)
// for graph problems write it out a lot to find better solutions
// for math ones, try writing simpler formulas esp. in combinatorics
// unsorted doesn't mean it's decreasing smh
// be slow, write things down, read statement twice & look at examples before thinking
// in graph problems, see if it mentions that there can be 2 edges betw to verts or not, or if it's disconnected
// use fabs and eps
// when using bitset be aware it goes backwards
// for bipartite, for each area mark all as vis, try starting from 2 nodes, mark nodes as vis before start
// for uva read output requirements twice
// use log2(double)
// if doing intervals and using list before, go straight to recursive (1189 C)


Measured memory_bytes: 256