/**
 * Date: 14 Sep, 2019
 * Link:
 *
 * @author Prasad-Chaudhari
 * @linkedIn: https://www.linkedin.com/in/prasad-chaudhari-841655a6/
 * @git: https://github.com/Prasad-Chaudhari
 */
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Map;

public class newProgram9 {

    public static void main(String[] args) throws IOException {
        // TODO code application logic here
        FastIO in = new FastIO();
        int t = in.ni();
        // int t = 1;
        while (t-- > 0) {
            int n = in.ni();
            int m = in.ni();
            int a[][] = new int[n][m];
            int b[][] = new int[m][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    a[i][j] = in.ni();
                    b[j][i] = a[i][j];
                }
            }
            for (int i = 0; i < m; i++) {
                Arrays.sort(b[i]);
            }
            Data d[] = new Data[m];
            for (int i = 0; i < m; i++) {
                d[i] = new Data(-b[i][n - 1], i);
            }
            Arrays.sort(d);

            int col = Math.min(n, m);
            int c[][] = new int[n][col];
            for (int i = 0; i < col; i++) {
                for (int j = 0; j < n; j++) {
                    c[j][i] = a[j][d[i].b];
                }
            }
            // for (int i = 0; i < n; i++) {
            //     for (int j = 0; j < col; j++) {
            //         System.out.print(c[i][j] + " ");
            //     }
            //     System.out.println();
            // }
            System.out.println(ans(c, n, col, 0));
        }
        in.bw.flush();
    }

    private static int ans(int c[][], int n, int m, int col) {
        if (col == m) {
            int sum = 0;
            for (int i = 0; i < n; i++) {
                int max = 0;
                for (int j = 0; j < m; j++) {
                    // System.out.print(c[i][j] + " ");
                    max = Math.max(c[i][j], max);
                }
                sum += max;
                // System.out.println();
            }
            // System.out.println(sum);
            return sum;
        } else {
            int max = ans(c, n, m, col + 1);
            int curr[] = new int[n];
            for (int i = 0; i < n; i++) {
                curr[i] = c[i][col];
            }
            for (int i = 1; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    c[j][col] = curr[(i + j) % n];
                }
                max = Math.max(max, ans(c, n, m, col + 1));
            }
            return max;
        }
    }

    static class FastIO {

        private final BufferedReader br;
        private final BufferedWriter bw;
        private String s[];
        private int index;
        private final StringBuilder sb;

        public FastIO() throws IOException {
            br = new BufferedReader(new InputStreamReader(System.in));
            bw = new BufferedWriter(new OutputStreamWriter(System.out, "UTF-8"));
            s = br.readLine().split(" ");
            sb = new StringBuilder();
            index = 0;
        }

        public int ni() throws IOException {
            return Integer.parseInt(nextToken());
        }

        public double nd() throws IOException {
            return Double.parseDouble(nextToken());
        }

        public long nl() throws IOException {
            return Long.parseLong(nextToken());
        }

        public String next() throws IOException {
            return nextToken();
        }

        public String nli() throws IOException {
            try {
                return br.readLine();
            } catch (IOException ex) {

            }
            return null;
        }

        public int[] gia(int n) throws IOException {
            int a[] = new int[n];
            for (int i = 0; i < n; i++) {
                a[i] = ni();
            }
            return a;
        }

        public int[] gia(int n, int start, int end) throws IOException {
            validate(n, start, end);
            int a[] = new int[n];
            for (int i = start; i < end; i++) {
                a[i] = ni();
            }
            return a;
        }

        public double[] gda(int n) throws IOException {
            double a[] = new double[n];
            for (int i = 0; i < n; i++) {
                a[i] = nd();
            }
            return a;
        }

        public double[] gda(int n, int start, int end) throws IOException {
            validate(n, start, end);
            double a[] = new double[n];
            for (int i = start; i < end; i++) {
                a[i] = nd();
            }
            return a;
        }

        public long[] gla(int n) throws IOException {
            long a[] = new long[n];
            for (int i = 0; i < n; i++) {
                a[i] = nl();
            }
            return a;
        }

        public long[] gla(int n, int start, int end) throws IOException {
            validate(n, start, end);
            long a[] = new long[n];
            for (int i = start; i < end; i++) {
                a[i] = nl();
            }
            return a;
        }

        public int[][][] gwtree(int n) throws IOException {
            int m = n - 1;
            int adja[][] = new int[n + 1][];
            int weight[][] = new int[n + 1][];
            int from[] = new int[m];
            int to[] = new int[m];
            int count[] = new int[n + 1];
            int cost[] = new int[n + 1];
            for (int i = 0; i < m; i++) {
                from[i] = i + 1;
                to[i] = ni();
                cost[i] = ni();
                count[from[i]]++;
                count[to[i]]++;
            }
            for (int i = 0; i <= n; i++) {
                adja[i] = new int[count[i]];
                weight[i] = new int[count[i]];
            }
            for (int i = 0; i < m; i++) {
                adja[from[i]][count[from[i]] - 1] = to[i];
                adja[to[i]][count[to[i]] - 1] = from[i];
                weight[from[i]][count[from[i]] - 1] = cost[i];
                weight[to[i]][count[to[i]] - 1] = cost[i];
                count[from[i]]--;
                count[to[i]]--;
            }
            return new int[][][] { adja, weight };
        }

        public int[][][] gwg(int n, int m) throws IOException {
            int adja[][] = new int[n + 1][];
            int weight[][] = new int[n + 1][];
            int from[] = new int[m];
            int to[] = new int[m];
            int count[] = new int[n + 1];
            int cost[] = new int[n + 1];
            for (int i = 0; i < m; i++) {
                from[i] = ni();
                to[i] = ni();
                cost[i] = ni();
                count[from[i]]++;
                count[to[i]]++;
            }
            for (int i = 0; i <= n; i++) {
                adja[i] = new int[count[i]];
                weight[i] = new int[count[i]];
            }
            for (int i = 0; i < m; i++) {
                adja[from[i]][count[from[i]] - 1] = to[i];
                adja[to[i]][count[to[i]] - 1] = from[i];
                weight[from[i]][count[from[i]] - 1] = cost[i];
                weight[to[i]][count[to[i]] - 1] = cost[i];
                count[from[i]]--;
                count[to[i]]--;
            }
            return new int[][][] { adja, weight };
        }

        public int[][] gtree(int n) throws IOException {
            int adja[][] = new int[n + 1][];
            int from[] = new int[n - 1];
            int to[] = new int[n - 1];
            int count[] = new int[n + 1];
            for (int i = 0; i < n - 1; i++) {
                from[i] = i + 1;
                to[i] = ni();
                count[from[i]]++;
                count[to[i]]++;
            }
            for (int i = 0; i <= n; i++) {
                adja[i] = new int[count[i]];
            }
            for (int i = 0; i < n - 1; i++) {
                adja[from[i]][--count[from[i]]] = to[i];
                adja[to[i]][--count[to[i]]] = from[i];
            }
            return adja;
        }

        public int[][] gg(int n, int m) throws IOException {
            int adja[][] = new int[n + 1][];
            int from[] = new int[m];
            int to[] = new int[m];
            int count[] = new int[n + 1];
            for (int i = 0; i < m; i++) {
                from[i] = ni();
                to[i] = ni();
                count[from[i]]++;
                count[to[i]]++;
            }
            for (int i = 0; i <= n; i++) {
                adja[i] = new int[count[i]];
            }
            for (int i = 0; i < m; i++) {
                adja[from[i]][--count[from[i]]] = to[i];
                adja[to[i]][--count[to[i]]] = from[i];
            }
            return adja;
        }

        public void print(String s) throws IOException {
            bw.write(s);
        }

        public void println(String s) throws IOException {
            bw.write(s);
            bw.newLine();
        }

        public void print(int s) throws IOException {
            bw.write(s + "");
        }

        public void println(int s) throws IOException {
            bw.write(s + "");
            bw.newLine();
        }

        public void print(long s) throws IOException {
            bw.write(s + "");
        }

        public void println(long s) throws IOException {
            bw.write(s + "");
            bw.newLine();
        }

        public void print(double s) throws IOException {
            bw.write(s + "");
        }

        public void println(double s) throws IOException {
            bw.write(s + "");
            bw.newLine();
        }

        private String nextToken() throws IndexOutOfBoundsException, IOException {
            if (index == s.length) {
                s = br.readLine().split(" ");
                index = 0;
            }
            return s[index++];
        }

        private void validate(int n, int start, int end) {
            if (start < 0 || end >= n) {
                throw new IllegalArgumentException();
            }
        }
    }

    static class Data implements Comparable<Data> {

        int a, b;

        public Data(int a, int b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public int compareTo(Data o) {
            if (a == o.a) {
                return Integer.compare(b, o.b);
            }
            return Integer.compare(a, o.a);
        }

        public static void sort(int a[]) {
            Data d[] = new Data[a.length];
            for (int i = 0; i < a.length; i++) {
                d[i] = new Data(a[i], 0);
            }
            Arrays.sort(d);
            for (int i = 0; i < a.length; i++) {
                a[i] = d[i].a;
            }
        }
    }
}


import java.io.*;
import java.util.*;

public class A {
    FastScanner in;
    PrintWriter out;

    void solve() {
        int tc = in.nextInt();
        for (int t = 0; t < tc; t++) {
            int n = in.nextInt();
            int m = in.nextInt();
            O[] a = new O[n * m];
            int[][] cols = new int[m][n + n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    cols[j][i] = cols[j][i + n] = in.nextInt();
                    a[i * m + j] = new O(i, j, cols[j][i]);
                }
            }
            Arrays.sort(a);
            boolean[] used = new boolean[m];
            int cntUsed = 0;
            for (O o : a) {
                if (!used[o.y]) {
                    used[o.y] = true;
                    cntUsed++;
                    if (cntUsed == n) {
                        break;
                    }
                }
            }
            int[] dp = new int[1 << n];
            int[] ndp = new int[1 << n];
            int[] maxndp = new int[1 << n];
            for (int col = 0; col < m; col++) {
                if (!used[col]) {
                    continue;
                }
                int[] curColumn = cols[col];
                for (int shift = 0; shift < n; shift++) {
                    System.arraycopy(dp, 0, ndp, 0, ndp.length);
                    for (int mask = 0; mask < 1 << n; mask++) {
                        for (int bit = 0; bit < n; bit++) {
                            if (((1 << bit) & mask) == 0) {
                                int nmask = mask | (1 << bit);
                                ndp[nmask] = Math.max(ndp[nmask], ndp[mask] + curColumn[bit + shift]);
                            }
                        }
                    }
                    for (int i = 0; i < ndp.length; i++) {
                        maxndp[i] = Math.max(maxndp[i], ndp[i]);
                    }
                }
                int[] tmp = dp;
                dp = maxndp;
                maxndp = tmp;
            }
            out.println(dp[dp.length - 1]);
        }
    }

    class O implements Comparable<O> {
        int x, y, value;

        public O(int x, int y, int value) {
            this.x = x;
            this.y = y;
            this.value = value;
        }

        @Override
        public int compareTo(O o) {
            return -Integer.compare(value, o.value);
        }
    }

    void run() {
        try {
            in = new FastScanner(new File("A.in"));
            out = new PrintWriter(new File("A.out"));

            solve();

            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    void runIO() {

        in = new FastScanner(System.in);
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(File f) {
            try {
                br = new BufferedReader(new FileReader(f));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        public FastScanner(InputStream f) {
            br = new BufferedReader(new InputStreamReader(f));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return null;
                st = new StringTokenizer(s);
            }
            return st.nextToken();
        }

        boolean hasMoreTokens() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return false;
                st = new StringTokenizer(s);
            }
            return true;
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }

    public static void main(String[] args) {
        new A().runIO();
    }
}


/**
 * BaZ :D
 */
import java.util.*;
import java.io.*;
import static java.lang.Math.*;

public class Main
{
    static MyScanner scan;
    static PrintWriter pw;
    static long MOD = 1_000_000_007;
    static long INF = 1_000_000_000_000_000_000L;
    static long inf = 2_000_000_000;
    public static void main(String[] args) {
        new Thread(null, null, "BaZ", 1 << 27) {
            public void run() {
                try {
                    solve();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }.start();
    }
    static int n,m,need,a[][],dp[][][],real[][];
    static void solve() throws IOException
    {
        //initIo(true);
        initIo(false);
        StringBuilder sb = new StringBuilder();
        int t = ni();
        while(t-->0) {
            n = ni();
            m = ni();
            a = new int[n][m];
            for(int i=0;i<n;++i) {
                for(int j=0;j<m;++j) {
                    a[i][j] = ni();
                }
            }
            need = min(n,m);
            Pair max_in_cols[] = new Pair[m];
            for(int COL=0;COL<m;++COL) {
                int max = 0;
                for(int i=0;i<n;++i) {
                    max = max(max, a[i][COL]);
                }
                max_in_cols[COL] = new Pair(max, COL);
            }
            real = new int[n][need];
            Arrays.sort(max_in_cols);
            for(int i=0;i<need;++i) {
                int COL = max_in_cols[m-1-i].y;
                for(int j=0;j<n;++j) {
                    real[j][i] = a[j][COL];
                }
            }
//            pl("need : "+need);
//            pa("Real", real);
            dp = new int[need][n+1][(1<<n)];
            for(int i=0;i<need;++i) {
                for(int j=0;j<=n;++j) {
                    for(int k=0;k<(1<<n);++k) {
                        dp[i][j][k] = -1;
                    }
                }
            }
            pl(f(0, n, 0));
        }
        pw.flush();
        pw.close();
    }
    static int f(int idx, int bias, int mask) {
        //pl("idx: "+idx+" bias : "+bias + " mask : "+mask);
        if(idx==need) {
            return 0;
        }
        if(dp[idx][bias][mask]!=-1) {
            return dp[idx][bias][mask];
        }

        //didn't fix bias yet
        if(bias==n) {
            int max = 0;
            for(int b=0;b<n;++b) {
                max = max(max, f(idx, b, mask));
            }
            //pl("maxxxxxxx : "+max);
            dp[idx][bias][mask] = max;
            return max;
        }
        else {
            int max = f(idx+1, n, mask);
            for(int i=0;i<n;++i) {
                if((mask&(1<<i))==0) {
                    max = max(max, real[(i-bias+n)%n][idx] + f(idx, bias, mask | (1<<i)));
                }
            }
            //pl("max : "+max);
            dp[idx][bias][mask] = max;
            return max;
        }
    }
    static class Pair implements Comparable<Pair>
    {
        int x,y;
        Pair(int x,int y)
        {
            this.x=x;
            this.y=y;
        }
        public int compareTo(Pair other)
        {
            if(this.x!=other.x)
                return this.x-other.x;
            return this.y-other.y;
        }
        public String toString()
        {
            return "("+x+","+y+")";
        }
    }
    static void initIo(boolean isFileIO) throws IOException {
        scan = new MyScanner(isFileIO);
        if(isFileIO) {
            pw = new PrintWriter("/Users/amandeep/Desktop/output.txt");
        }
        else {
            pw = new PrintWriter(System.out, true);
        }
    }
    static int ni() throws IOException
    {
        return scan.nextInt();
    }
    static long nl() throws IOException
    {
        return scan.nextLong();
    }
    static double nd() throws IOException
    {
        return scan.nextDouble();
    }
    static String ne() throws IOException
    {
        return scan.next();
    }
    static String nel() throws IOException
    {
        return scan.nextLine();
    }
    static void pl()
    {
        pw.println();
    }
    static void p(Object o)
    {
        pw.print(o+" ");
    }
    static void pl(Object o)
    {
        pw.println(o);
    }
    static void psb(StringBuilder sb)
    {
        pw.print(sb);
    }
    static void pa(String arrayName, Object arr[])
    {
        pl(arrayName+" : ");
        for(Object o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, int arr[])
    {
        pl(arrayName+" : ");
        for(int o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, long arr[])
    {
        pl(arrayName+" : ");
        for(long o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, double arr[])
    {
        pl(arrayName+" : ");
        for(double o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, char arr[])
    {
        pl(arrayName+" : ");
        for(char o : arr)
            p(o);
        pl();
    }
    static void pa(String listName, List list)
    {
        pl(listName+" : ");
        for(Object o : list)
            p(o);
        pl();
    }
    static void pa(String arrayName, Object[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(Object o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, int[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(int o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, long[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(long o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, char[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(char o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, double[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(double o : arr[i])
                p(o);
            pl();
        }
    }
    static class MyScanner
    {
        BufferedReader br;
        StringTokenizer st;
        MyScanner(boolean readingFromFile) throws IOException
        {
            if(readingFromFile) {
                br = new BufferedReader(new FileReader("/Users/amandeep/Desktop/input.txt"));
            }
            else {
                br = new BufferedReader(new InputStreamReader(System.in));
            }
        }
        String nextLine()throws IOException
        {
            return br.readLine();
        }
        String next() throws IOException
        {
            if(st==null || !st.hasMoreTokens())
                st = new StringTokenizer(br.readLine());
            return st.nextToken();
        }
        int nextInt() throws IOException
        {
            return Integer.parseInt(next());
        }
        long nextLong() throws IOException
        {
            return Long.parseLong(next());
        }
        double nextDouble() throws IOException
        {
            return Double.parseDouble(next());
        }
    }
}


import java.util.*;
import java.math.*;

// **** E1. Rotate Columns (easy version) ****

public class E1 {
	static char [] in = new char [1000000];
	public static void main (String [] arg) throws Throwable {
		int t = nextInt();
		C : for (int ii = 0; ii<t; ++ii) {
			int n = nextInt();
			int m = nextInt();
			Pair [] P = new Pair [n*m];
			int [][] g = new int [n][m];
			for (int i = 0; i<n; ++i) {
				for (int j = 0; j<m; ++j) {
					g[i][j] = nextInt();
					P[j + m*i] = new Pair (i, j, g[i][j]);
				}
			}
			for (int i = 0; i<P.length; ++i) if (P[i] == null) continue C;
			Arrays.sort(P);
			HashSet<Integer> rotcols =new HashSet<Integer>();
			for (int i = 0; i<n; ++i) {
				//System.err.println("Adding " + P[i].j + " , " + P[i].L);
				rotcols.add(P[i].j);
			}

			if (n <= 3 || rotcols.size() >= 3) {
				//System.err.println("EASY");
				int sum = 0;
				for (int i = 0; i<n && i < P.length; ++i) sum += P[i].L;
				System.out.println(sum);
			} else {
				// n == 4
				if (P.length > 4) rotcols.add(P[4].j);
				//Integer [] rr = rotcols.toArray(new Integer[0]);
				int [] rot = new int [rotcols.size()];
				int maxmax = 0;
				A : while (true) {
					for (int i = 0; i<rot.length; ++i) {
						rot[i]++;
						if (rot[i] == n) {
							rot[i] = 0;
							if (i == rot.length-1) break A;
						} else {
							break;
						}
					}
					int [] max = new int [n];
					for (int i = 0; i<n; ++i) {
						int j = 0;
						for (int col : rotcols) {
							max[i] = Math.max(max[i], g[(i+rot[j])%n][col]);
							j++;
						}
					}
					int sum = 0;
					for (int m2 : max) sum+= m2;
					maxmax = Math.max(maxmax, sum);
				}
				System.out.println(maxmax);
			}
		}
	}

	/************** HELPER CLASSES ***************/
    //static class HS extends HashSet<Integer>{public HS(){super();}public HS(int a){super(a);}};
	//static class AL extends ArrayList<Integer>{public AL(){super();}public AL(int a){super (a);}};
	static class Pair implements Comparable<Pair> {
		int i,j;long L; public Pair(int xx, int yy, long LL){i=xx;j=yy;L=LL;}
		public int compareTo(Pair p) { return (this.L > p.L) ? -1 : (this.L == p.L) ? this.i - p.i : 1;}
	}
	/************** FAST IO CODE FOLLOWS *****************/
	public static long nextLong() throws Throwable {
		long i = System.in.read();boolean neg = false;while (i < 33) i = System.in.read();if (i == 45) {neg=true;i=48;}i = i - 48;
		int j = System.in.read();while (j > 32) {i*=10;i+=j-48;j = System.in.read();}return (neg) ? -i : i;
	}
	public static int nextInt() throws Throwable {return (int)nextLong();}
	public static String next() throws Throwable {
		int i = 0; while (i < 33 && i != -1) i = System.in.read(); int cptr = 0; while (i >= 33) { in[cptr++] = (char)i; i = System.in.read();}
		return new String(in, 0,cptr);
	}
	/**** LIBRARIES ****/
	public static long gcdL(long a, long b) {while (b != 0) {long tmp = b;b = (a % b);a = tmp;}return a;}
	public static int gcd(int a, int b) {while (b != 0) {int tmp = b;b = (a % b);a = tmp;}return a;}
	public static int[] sieve(int LIM) {
		int i,count = 0;
		boolean [] b = new boolean [LIM];
		for (i = 2;i<LIM; ++i) if (!b[i]) {count++; for (int j = i<<1; j<LIM; j+=i) b[j] = true;}
		int [] primes = new int[count];
		for (i = 2,count=0;i<LIM;++i) if (!b[i]) primes[count++] = i;
		return primes;
	}
	public static int[] numPrimeFactors(int LIM) {
		int i,count = 0;
		int [] b = new int [LIM];
		for (i = 2;i<LIM; ++i) if (b[i] == 0) {count++; for (int j = i; j<LIM; j+=i) b[j]++;}
		return b;
	}
	public static StringBuilder stringFromArray(int [] a) {
		StringBuilder b = new StringBuilder(9*a.length);
		for (int i = 0; i<a.length; ++i) {
			if (i != 0) b = b.append(' ');
			b = b.append(a[i]);
		}
		return b;
	}
	public static long modPow (long a, long n, long MOD) { long S = 1; for (;n > 0; n>>=1, a=(a*a)%MOD) if ((n & 1) != 0) S = (a*S) % MOD; return S;}
}

/* Full Problem Text:

This is an easier version of the next problem.
The difference is only in constraints.
You are given a rectangular n \times m matrix a.
In one move you can choose any column and cyclically shift elements in this column.
You can perform this operation as many times as you want (possibly zero).
You can perform this operation to a column multiple times.
After you are done with cyclical shifts, you compute for every row the maximal value in it.
Suppose that for i-th row it is equal r_i.
What is the maximal possible value of r_1+r_2+...+r_n?

 */


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.FilterInputStream;
import java.io.BufferedInputStream;
import java.util.Random;
import java.io.InputStream;

/**
 * @author khokharnikunj8
 */

public class Main {
    public static void main(String[] args) {
        new Thread(null, new Runnable() {
            public void run() {
                new Main().solve();
            }
        }, "1", 1 << 26).start();
    }

    void solve() {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = in.scanInt();
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        int[][] dp;
        int[] cur;

        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            int m = in.scanInt();
            int[][] ar = new int[n][m];
            int[][] max = new int[m][2];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    ar[i][j] = in.scanInt();
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) max[i][0] = Math.max(max[i][0], ar[j][i]);
                max[i][1] = i;
            }
            CodeHash.shuffle(max);
            Arrays.sort(max, (o1, o2) -> -o1[0] + o2[0]);
            dp = new int[2][1 << n];
            cur = new int[1 << n];
            for (int i = 0; i < Math.min(m, n); i++) {
                Arrays.fill(dp[i & 1], 0);
                for (int k = 0; k < n; k++) {
                    System.arraycopy(dp[(i - 1) & 1], 0, cur, 0, 1 << n);
                    for (int l = 0; l < n; l++) {
                        for (int j = 0; j < 1 << n; j++) {
                            if ((j & (1 << l)) == 0) {
                                cur[j ^ (1 << l)] = Math.max(cur[j ^ (1 << l)], cur[j] + ar[(k + l) % n][max[i][1]]);
                            }
                        }
                    }
                    for (int j = 0; j < 1 << n; j++) dp[i & 1][j] = Math.max(dp[i & 1][j], cur[j]);
                }
            }
            out.println(dp[Math.min(n, m) & 1 ^ 1][(1 << n) - 1]);
        }

    }

    static class CodeHash {
        public static void shuffle(int[][] ar) {
            Random rd = new Random(new Random().nextInt());
            for (int i = 0; i < ar.length; i++) {
                int index = rd.nextInt(ar.length);
                int[] temp = ar[i];
                ar[i] = ar[index];
                ar[index] = temp;
            }
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int index;
        private BufferedInputStream in;
        private int total;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (index >= total) {
                index = 0;
                try {
                    total = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (total <= 0) return -1;
            }
            return buf[index++];
        }

        public int scanInt() {
            int integer = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    integer *= 10;
                    integer += n - '0';
                    n = scan();
                }
            }
            return neg * integer;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

    }
}


import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.IntStream;

public class Test {
  static PrintWriter writer =
      new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

  static int readInt() {
    int ans = 0;
    boolean neg = false;
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c == '-') {
          start = true;
          neg = true;
          continue;
        } else if (c >= '0' && c <= '9') {
          start = true;
          ans = ans * 10 + c - '0';
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return neg ? -ans : ans;
  }

  static long readLong() {
    long ans = 0;
    boolean neg = false;
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c == '-') {
          start = true;
          neg = true;
          continue;
        } else if (c >= '0' && c <= '9') {
          start = true;
          ans = ans * 10 + c - '0';
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return neg ? -ans : ans;
  }

  static String readLine() {
    StringBuilder b = new StringBuilder();
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (Character.isLetterOrDigit(c)) {
          start = true;
          b.append((char) c);
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return b.toString();
  }

  public static void main(String[] args) {
    Test te = new Test();
    te.start();
    writer.flush();
  }

  int[] buf = new int[10];

  int best(int[][] a, int c) {
    int ans = 0;
    if (c == a[0].length) {
      for (int i = 0; i < a.length; i++)
        ans += Arrays.stream(a[i]).max().getAsInt();
      return ans;
    }
    for (int r = 0; r <= a.length; r++) {
      for (int i = 0; i < a.length; i++)
        buf[(i+1) % a.length] = a[i][c];
      for (int i = 0; i < a.length; i++)
        a[i][c] = buf[i];
      ans = Math.max(ans, best(a, c+1));
    }
    return ans;
  }

  void start() {
    int t = readInt();
    while (t-- > 0) {
      int n = readInt(), m = readInt();
      int[][] a = new int[n][m];
      int[][] e = new int[n*m][];
      for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
          a[i][j] = readInt();
          e[i*m+j] = new int[]{a[i][j], j};
        }
      Arrays.sort(e, (x, y) -> x[0] == y[0] ? Integer.compare(x[1], y[1])
          : Integer.compare(y[0], x[0]));
      Set<Integer> cols = new HashSet<>();
      for (int[] x : e) {
        cols.add(x[1]);
        if (cols.size() >= n) break;
      }
      int[] cs = cols.stream().mapToInt(Integer::intValue).toArray();
      int[][] na = new int[n][cs.length];
      for (int i = 0; i < n; i++)
        for (int j = 0; j < cs.length; j++)
          na[i][j] = a[i][cs[j]];
      writer.println(best(na, 0));
    }
  }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        Scanner in = new Scanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2VrashayaStolbciUslozhnennayaVersiya solver = new E2VrashayaStolbciUslozhnennayaVersiya();
        solver.solve(1, in, out);
        out.close();
    }

    static class E2VrashayaStolbciUslozhnennayaVersiya {
        public void solve(int testNumber, Scanner in, PrintWriter out) {
            int tn = in.nextInt();
            for (int t = 0; t < tn; t++) {
                int n = in.nextInt();
                int m = in.nextInt();
                Col[] a = new Col[m];
                for (int i = 0; i < m; i++) {
                    a[i] = new Col(n);
                }
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < m; j++) {
                        a[j].a[i] = in.nextInt();
                        if (a[j].a[i] > a[j].max) {
                            a[j].max = a[j].a[i];
                        }
                    }

                }

                Arrays.sort(a, (o1, o2) -> o2.max - o1.max);

                if (m > n) {
                    m = n;
                }

                for (int i = 0; i < m; i++) {
                    a[i].calcMask();
                }

                int[][] dp = new int[m + 1][1 << n];
                Arrays.fill(dp[0], -1);
                dp[0][0] = 0;
                for (int i = 0; i < m; i++) {
                    for (int msk = 0; msk < (1 << n); msk++) {
                        dp[i + 1][msk] = dp[i][msk];
                        for (int sub = msk; sub > 0; sub = (sub - 1) & msk) {
                            int v = dp[i][msk ^ sub] + a[i].mask[sub];
                            if (v > dp[i + 1][msk]) {
                                dp[i + 1][msk] = v;
                            }
                        }
                    }
                }

                out.println(dp[m][(1 << n) - 1]);
            }
        }

        class Col {
            int n;
            int[] a;
            int[] mask;
            int max;

            public Col(int n) {
                this.n = n;
                a = new int[n];
            }

            void calcMask() {
                mask = new int[1 << n];
                for (int i = 0; i < (1 << n); i++) {
                    for (int j = 0; j < n; j++) {
                        int sum = 0;
                        for (int k = 0; k < n; k++) {
                            if (((1 << k) & i) != 0) {
                                sum += a[(j + k) % n];
                            }
                        }
                        if (sum > mask[i]) {
                            mask[i] = sum;
                        }
                    }
                }
            }

        }

    }
}


import java.util.*;
import java.io.*;
public class E584 {
    public static void main(String[] args) {
        MyScanner sc = new MyScanner();
        PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
        int t = sc.nextInt();
        while (t > 0) {
            int n = sc.nextInt(); int m = sc.nextInt();
            int [][] a = new int[m][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    a[j][i] = sc.nextInt();
                }
            }
            int [][] dp = new int[m + 1][(1 << n)];
            for (int i = 1; i <= m; i++) {
                for (int j = 0; j < (1 << n); j++) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
                    int [] b = a[i - 1];
                    for (int start = 0; start < n; start++) {
                        int [] c = new int[n];
                        for (int p = 0; p < n; p++) c[p] = b[(start + p) % n];
                        for (int k = 0; k < (1 << n); k++) {
                            if ((k | j) == j) {
                                int sum = 0;
                                for (int p = 0; p < n; p++) {
                                    if (((k >> p) & 1) == 0 && ((j >> p) & 1) == 1) sum += c[p];
                                }
                                dp[i][j] = Math.max(dp[i][j], dp[i - 1][k] + sum);
                            }
                        }
                    }
                }
            }
            out.println(dp[m][(1 << n) - 1]);
            t--;
        }

        out.close();
    }

    //-----------MyScanner class for faster input----------
    public static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

        public MyScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

    }

}


import java.util.*;
public class Main {
    public static class Pair implements Comparable<Pair> {
        int k, x;
        public Pair(int k) {
            this.k = k;
        }
        public void update(int x) {
            this.x = Math.max(this.x, x);
        }
        public int compareTo(Pair other) {
            if (x != other.x) {
                return other.x - x;
            }
            return k - other.k;
        }
    }
    public static int sum(int[] arr) {
        int sum = 0;
        for (int x : arr) {
            sum += x;
        }
        return sum;
    }
    public static int[] join(int[] a, int[] b) {
        int n = a.length;
        int[] best = new int[n];
        int sum = 0;
        for (int shift = 0; shift < n; shift++) {
            int[] curr = new int[n];
            for (int i = 0; i < n; i++) {
                curr[i] = Math.max(a[i], b[(i + shift) % n]);
            }
            int now = sum(curr);
            if (now > sum) {
                sum = now;
                best = curr;
            }
        }
        return best;
    }
    public static int n;
    public static int[] pow;
    public static int[][] dp, real;
    public static void calc(int mask) {
        int[] best = new int[n];
        int sum = 0;
        for (int i = 0; i < n; i++) {
            if ((mask & pow[i]) != 0) {
                int to = mask ^ pow[i];
                int[] init = new int[n];
                for (int j = 0; j < n; j++) {
                    init[j] = real[j][i];
                }
                int[] curr = join(dp[to], init);
                int s = sum(curr);
                if (s > sum) {
                    sum = s;
                    best = curr;
                }
            }
        }
        dp[mask] = best;
    }
    public static void main(String[] args) {
        pow = new int[15];
        pow[0] = 1;
        for (int i = 1; i < pow.length; i++) {
            pow[i] = pow[i - 1] * 2;
        }
        Scanner in = new Scanner(System.in);
        int t = in.nextInt();
        for (int i = 0; i < t; i++) {
            n = in.nextInt();
            int m = in.nextInt();
            int[][] arr = new int[n][m];
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < m; k++) {
                    arr[j][k] = in.nextInt();
                }
            }
            Pair[] best = new Pair[m];
            for (int j = 0; j < m; j++) {
                best[j] = new Pair(j);
                for (int k = 0; k < n; k++) {
                    best[j].update(arr[k][j]);
                }
            }
            Arrays.sort(best);
            real = new int[n][n];
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < Math.min(n, m); k++) {
                    real[j][k] = arr[j][best[k].k];
                }
            }
            dp = new int[1 << n][];
            Stack<Integer>[] min = new Stack[n + 1];
            for (int j = 0; j <= n; j++) {
                min[j] = new Stack<>();
            }
            for (int j = 0; j < dp.length; j++) {
                int cnt = 0;
                for (int k = 0; k < n; k++) {
                    if ((j & pow[k]) != 0) {
                        cnt++;
                    }
                }
                min[cnt].add(j);
            }
            for (int j = 0; j < min.length; j++) {
                for (int x : min[j]) {
                    if (j == 0) {
                        dp[x] = new int[n];
                    } else {
                        calc(x);
                    }
                }
            }
            System.out.println(sum(dp[dp.length - 1]));
        }
    }
}


import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.*;

public class CFContest {
    public static void main(String[] args) throws Exception {
        boolean local = System.getProperty("ONLINE_JUDGE") == null;
        boolean async = true;

        Charset charset = Charset.forName("ascii");

        FastIO io = local ? new FastIO(new FileInputStream("D:\\DATABASE\\TESTCASE\\Code.in"), System.out, charset) : new FastIO(System.in, System.out, charset);
        Task task = new Task(io, new Debug(local));

        if (async) {
            Thread t = new Thread(null, task, "dalt", 1 << 27);
            t.setPriority(Thread.MAX_PRIORITY);
            t.start();
            t.join();
        } else {
            task.run();
        }

        if (local) {
            io.cache.append("\n\n--memory -- \n" + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20) + "M");
        }

        io.flush();
    }

    public static class Task implements Runnable {
        final FastIO io;
        final Debug debug;
        int inf = (int) 1e8;
        long lInf = (long) 1e18;

        public Task(FastIO io, Debug debug) {
            this.io = io;
            this.debug = debug;
        }

        @Override
        public void run() {
            int t = io.readInt();
            while (t-- > 0)
                solve1();
        }

        public void solve1() {
            cache.clear();
            int n = io.readInt();
            int m = io.readInt();
            Col[] mat = new Col[m];
            for (int i = 0; i < m; i++) {
                mat[i] = new Col();
                mat[i].data = new int[n];
            }

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    int v = io.readInt();
                    mat[j].data[i] = v;
                    mat[j].max = Math.max(mat[j].max, v);
                }
            }

            Arrays.sort(mat, (a, b) -> -(a.max - b.max));
            mat = Arrays.copyOf(mat, Math.min(n, m));
            io.cache.append(bf(mat, getCol(n), n, 0)).append('\n');
        }

        public void enhance(Col mask, Col c, Col ans, int n) {
            for (int i = 0; i < n; i++) {
                ans.data[i] = Math.max(mask.get(i), c.get(i));
            }
        }

        Deque<Col> cache = new ArrayDeque<>();

        public Col getCol(int n) {
            if (cache.isEmpty()) {
                Col col = new Col();
                col.data = new int[n];
                return col;
            }
            return cache.removeFirst();
        }

        public void destroy(Col c) {
            c.offset = 0;
            c.max = 0;
            cache.addLast(c);
        }

        public int bf(Col[] cols, Col mask, int n, int k) {
            if (k >= cols.length) {
                int sum = 0;
                for (int i = 0; i < n; i++) {
                    sum += mask.data[i];
                }
                return sum;
            }

            int max = 0;
            cols[k].offset = 0;

            for (int i = 0; i < n; i++) {
                Col c = getCol(n);
                enhance(mask, cols[k], c, n);
                max = Math.max(max, bf(cols, c, n, k + 1));
                destroy(c);
                cols[k].turn();
            }

            return max;
        }

    }

    public static class Col {
        int[] data;
        int offset;

        public int get(int i) {
            return data[(i + offset) % data.length];
        }

        public void turn() {
            offset++;
        }

        int max;
    }

    public static class FastIO {
        public final StringBuilder cache = new StringBuilder(20 << 20);
        private final InputStream is;
        private final OutputStream os;
        private final Charset charset;
        private StringBuilder defaultStringBuf = new StringBuilder(1 << 8);
        private byte[] buf = new byte[1 << 20];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastIO(InputStream is, OutputStream os, Charset charset) {
            this.is = is;
            this.os = os;
            this.charset = charset;
        }

        public FastIO(InputStream is, OutputStream os) {
            this(is, os, Charset.forName("ascii"));
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public long readLong() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            long val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public double readDouble() {
            boolean sign = true;
            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+';
                next = read();
            }

            long val = 0;
            while (next >= '0' && next <= '9') {
                val = val * 10 + next - '0';
                next = read();
            }
            if (next != '.') {
                return sign ? val : -val;
            }
            next = read();
            long radix = 1;
            long point = 0;
            while (next >= '0' && next <= '9') {
                point = point * 10 + next - '0';
                radix = radix * 10;
                next = read();
            }
            double result = val + (double) point / radix;
            return sign ? result : -result;
        }

        public String readString(StringBuilder builder) {
            skipBlank();

            while (next > 32) {
                builder.append((char) next);
                next = read();
            }

            return builder.toString();
        }

        public String readString() {
            defaultStringBuf.setLength(0);
            return readString(defaultStringBuf);
        }

        public int readLine(char[] data, int offset) {
            int originalOffset = offset;
            while (next != -1 && next != '\n') {
                data[offset++] = (char) next;
                next = read();
            }
            return offset - originalOffset;
        }

        public int readString(char[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (char) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public int readString(byte[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (byte) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public char readChar() {
            skipBlank();
            char c = (char) next;
            next = read();
            return c;
        }

        public void flush() {
            try {
                os.write(cache.toString().getBytes(charset));
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        public boolean hasMore() {
            skipBlank();
            return next != -1;
        }
    }

    public static class Debug {
        private boolean allowDebug;

        public Debug(boolean allowDebug) {
            this.allowDebug = allowDebug;
        }

        public void assertTrue(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (!flag) {
                fail();
            }
        }

        public void fail() {
            throw new RuntimeException();
        }

        public void assertFalse(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (flag) {
                fail();
            }
        }

        private void outputName(String name) {
            System.out.print(name + " = ");
        }

        public void debug(String name, int x) {
            if (!allowDebug) {
                return;
            }

            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, long x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, double x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, int[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, long[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, double[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, Object x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, Object... x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.deepToString(x));
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author anand.oza
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E1RotateColumnsEasyVersion solver = new E1RotateColumnsEasyVersion();
        solver.solve(1, in, out);
        out.close();
    }

    static class E1RotateColumnsEasyVersion {
        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int t = in.nextInt();
            for (int i = 0; i < t; i++) {
                solve(in, out);
            }
        }

        private void solve(InputReader in, PrintWriter out) {
            int n = in.nextInt(), m = in.nextInt();

            int[][] a = new int[n][];
            for (int i = 0; i < n; i++) {
                a[i] = in.readIntArray(m);
            }

            out.println(solve(n, m, a));
        }

        private int solve(int n, int m, int[][] a) {
            Cell[] cells = new Cell[n * m];
            for (int i = 0, index = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    cells[index++] = new Cell(i, j, a[i][j]);
                    if (index == cells.length)
                        break;
                }
            }

            Arrays.sort(cells, Comparator.comparingInt(cell -> -cell.x));

            HashSet<Integer> colset = new HashSet<>();
            for (int i = 0; colset.size() < n && colset.size() < m; i++) {
                colset.add(cells[i].j);
            }

            ArrayList<Integer> cols = new ArrayList<>();
            cols.addAll(colset);

            int answer = 0;
            for (long perm = 0; perm < pow(n, cols.size() - 1); perm++) {
                long p = perm;
                int[] offset = new int[cols.size()];
                for (int col = 0; col < cols.size(); col++) {
                    offset[col] = (int) (p % n);
                    p /= n;
                }
                int sum = 0;
                for (int row = 0; row < n; row++) {
                    int max = 0;
                    for (int col = 0; col < cols.size(); col++) {
                        int cur = a[(row + offset[col]) % n][cols.get(col)];
                        max = Math.max(max, cur);
                    }
                    sum += max;
                }
                answer = Math.max(answer, sum);
            }

            return answer;
        }

        private long pow(int base, int exponent) {
            long p = 1;
            for (int i = 0; i < exponent; i++) {
                p *= base;
            }
            return p;
        }

        private class Cell {
            final int i;
            final int j;
            final int x;

            private Cell(int i, int j, int x) {
                this.i = i;
                this.j = j;
                this.x = x;
            }

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public int[] readIntArray(int n) {
            int[] x = new int[n];
            for (int i = 0; i < n; i++) {
                x[i] = nextInt();
            }
            return x;
        }

    }
}


import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import java.math.*;

public class E1 {
	static byte[] buf = new byte[1<<26];
    static int bp = -1;

	public static void main(String[] args) throws IOException {

		/**/
		DataInputStream in = new DataInputStream(System.in);
		/*/
		DataInputStream in = new DataInputStream(new FileInputStream("src/e.in"));
		/**/

		in.read(buf, 0, 1<<26);
		int t = nni();
		for (int z = 0; z < t; z++) {
			int n = nni();
			int m = nni();
			int[][] mat = new int[n][m];
			int[] rmax = new int[n];
			int tot = 0;
			HashSet<Integer> care = new HashSet<>();
			for (int i = 0; i < n; i++) {
				PriorityQueue<Integer> cols = new PriorityQueue<>();
				for (int j = 0; j < m; j++) {
					mat[i][j] = nni();
					cols.add(-(mat[i][j]*2000+j));
					rmax[i] = Math.max(rmax[i], mat[i][j]);
				}
				tot += rmax[i];
				for (int j = 0; j < Math.min(m, n); j++)
					care.add((-cols.poll())%2000);
			}
			List<Integer> cal = care.stream().sorted().collect(Collectors.toList());
			int ret = tot;
			if (Math.min(m, n)==1) {
				System.out.println(ret);
			} else if (Math.min(m, n)==2) {
				for (int a = 0; a < cal.size(); a++) {
					int la = cal.get(a);
					for (int d = 0; d < cal.size(); d++) {
						if (d==a)
							continue;
						int ld = cal.get(d);
						for (int i = 0; i < n; i++) {
							int tret = 0;
							for (int x = 0; x < n; x++) {
								tret += Math.max(mat[x][ld], mat[(i+x)%n][la]);
							}
							ret = Math.max(ret, tret);
						}
					}
				}
				System.out.println(ret);
			} else if (Math.min(m, n)==3) {
				for (int a = 0; a < cal.size(); a++) {
					int la = cal.get(a);
					for (int b = a+1; b < cal.size(); b++) {
						int lb = cal.get(b);
						for (int d = 0; d < cal.size(); d++) {
							if (d==a)
								continue;
							if (d==b)
								continue;
							int ld = cal.get(d);
							for (int i = 0; i < n; i++) {
								for (int j = 0; j < n; j++) {
									int tret = 0;
									for (int x = 0; x < n; x++) {
										tret += Math.max(mat[x][ld], Math.max(mat[(i+x)%n][la], mat[(j+x)%n][lb]));
									}
									ret = Math.max(ret, tret);
								}
							}
						}
					}
				}
				System.out.println(ret);
			} else if (Math.min(m, n)==4) {
				for (int a = 0; a < cal.size(); a++) {
					int la = cal.get(a);
					for (int b = a+1; b < cal.size(); b++) {
						int lb = cal.get(b);
						for (int c = b+1; c < cal.size(); c++) {
							int lc = cal.get(c);
							for (int d = 0; d < cal.size(); d++) {
								if (d==a)
									continue;
								if (d==b)
									continue;
								if (d==c)
									continue;
								int ld = cal.get(d);
								for (int i = 0; i < n; i++) {
									for (int j = 0; j < n; j++) {
										for (int k = 0; k < n; k++) {
											int tret = 0;
											for (int x = 0; x < n; x++) {
												tret += Math.max(mat[x][ld], Math.max(mat[(i+x)%n][la], Math.max(mat[(j+x)%n][lb], mat[(k+x)%n][lc])));
											}
											ret = Math.max(ret, tret);
										}
									}
								}
							}
						}
					}
				}
				System.out.println(ret);
			}
		}
	}

	public static int nni() {
        int ret = 0;
        byte b = buf[++bp];
        while (true) {
            ret = ret*10+b-'0';
            b = buf[++bp];
            if (b<'0'||b>'9') {
            	while (buf[bp+1]=='\r'||buf[bp+1]=='\n'||buf[bp+1]==' ') {++bp;}
            	break;
            }
        }
        return ret;
    }
}


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;

public class Main {

	static PrintWriter out;
	static InputReader ir;

	static void solve() {
		int t = ir.nextInt();
		while (t-- > 0) {
			int n = ir.nextInt();
			int m = ir.nextInt();
			int[][] a = new int[n][];
			for (int i = 0; i < n; i++) {
				a[i] = ir.nextIntArray(m);
			}
			int[][][] comx = new int[n + 1][m][2];
			for (int i = 0; i < m; i++) {
				int[] b = new int[n];
				for (int j = 0; j < n; j++) {
					b[j] = a[j][i];
				}
				Arrays.sort(b);
				for (int j = 0; j < n; j++) {
					comx[j + 1][i][0] = comx[j][i][0] + b[n - 1 - j];
					comx[j + 1][i][1] = i;
				}
			}
			int[][][] org = new int[n + 1][m][2];
			for (int i = 0; i <= n; i++)
				for (int j = 0; j < m; j++) {
					for (int k = 0; k < 2; k++) {
						org[i][j][k] = comx[i][j][k];
					}
				}
			for (int i = 1; i <= n; i++)
				Arrays.sort(comx[i], new Comparator<int[]>() {
					public int compare(int[] A, int[] B) {
						return A[0] - B[0];
					}
				});
			// tr(org);
			// tr(comx);
			if (n == 1) {
				out.println(comx[1][m - 1][0]);
			} else if (n == 2) {
				out.println(Math.max(comx[2][m - 1][0], m >= 2 ? comx[1][m - 1][0] + comx[1][m - 2][0] : 0));
			} else if (n == 3) {
				int res = Math.max(comx[3][m - 1][0],
						m >= 3 ? comx[1][m - 1][0] + comx[1][m - 2][0] + comx[1][m - 3][0] : 0);
				if (m >= 2) {
					for (int i = 0; i < m; i++) {
						int p = comx[2][i][0];
						int ma = 0;
						for (int j = 0; j < m; j++) {
							if (comx[2][i][1] == j)
								continue;
							ma = Math.max(org[1][j][0], ma);
						}
						res = Math.max(res, p + ma);
					}
				}
				out.println(res);
			} else {
				int res = Math.max(comx[4][m - 1][0],
						m >= 4 ? comx[1][m - 1][0] + comx[1][m - 2][0] + comx[1][m - 3][0] + comx[1][m - 4][0] : 0);
				if (m >= 2) {
					for (int i = 0; i < m; i++) {
						int p = comx[3][i][0];
						int ma = 0;
						for (int j = 0; j < m; j++) {
							if (comx[3][i][1] == j)
								continue;
							ma = Math.max(org[1][j][0], ma);
						}
						res = Math.max(res, p + ma);
					}
				}
				if (m >= 3) {
					for (int i = 0; i < m; i++) {
						int p = comx[2][i][0];
						PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
						for (int j = 0; j < m; j++) {
							if (comx[2][i][1] == j)
								continue;
							pq.add(org[1][j][0]);
						}
						res = Math.max(res, p + pq.poll() + pq.poll());
					}
				}
				if (m >= 2) {
					for (int i = 0; i < m; i++) {
						int p = 0;
						for (int j = 0; j < 4; j++) {
							p = Math.max(p, a[j][i] + a[(j + 1) % 4][i]);
						}
						int ma = 0;
						for (int j = 0; j < m; j++) {
							if (i == j)
								continue;
							for (int k = 0; k < 4; k++) {
								ma = Math.max(ma, a[k][j] + a[(k + 1) % 4][j]);
							}
						}
						res = Math.max(res, p + ma);
					}
					for (int i = 0; i < m; i++) {
						int p = 0;
						for (int j = 0; j < 4; j++) {
							p = Math.max(p, a[j][i] + a[(j + 2) % 4][i]);
						}
						int ma = 0;
						for (int j = 0; j < m; j++) {
							if (i == j)
								continue;
							for (int k = 0; k < 4; k++) {
								ma = Math.max(ma, a[k][j] + a[(k + 2) % 4][j]);
							}
						}
						res = Math.max(res, p + ma);
					}
				}
				out.println(res);
			}
		}

	}

	public static void main(String[] args) {
		ir = new InputReader(System.in);
		out = new PrintWriter(System.out);
		solve();
		out.flush();
	}

	static class InputReader {

		private InputStream in;
		private byte[] buffer = new byte[1024];
		private int curbuf;
		private int lenbuf;

		public InputReader(InputStream in) {
			this.in = in;
			this.curbuf = this.lenbuf = 0;
		}

		public boolean hasNextByte() {
			if (curbuf >= lenbuf) {
				curbuf = 0;
				try {
					lenbuf = in.read(buffer);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (lenbuf <= 0)
					return false;
			}
			return true;
		}

		private int readByte() {
			if (hasNextByte())
				return buffer[curbuf++];
			else
				return -1;
		}

		private boolean isSpaceChar(int c) {
			return !(c >= 33 && c <= 126);
		}

		private void skip() {
			while (hasNextByte() && isSpaceChar(buffer[curbuf]))
				curbuf++;
		}

		public boolean hasNext() {
			skip();
			return hasNextByte();
		}

		public String next() {
			if (!hasNext())
				throw new NoSuchElementException();
			StringBuilder sb = new StringBuilder();
			int b = readByte();
			while (!isSpaceChar(b)) {
				sb.appendCodePoint(b);
				b = readByte();
			}
			return sb.toString();
		}

		public int nextInt() {
			if (!hasNext())
				throw new NoSuchElementException();
			int c = readByte();
			while (isSpaceChar(c))
				c = readByte();
			boolean minus = false;
			if (c == '-') {
				minus = true;
				c = readByte();
			}
			int res = 0;
			do {
				if (c < '0' || c > '9')
					throw new InputMismatchException();
				res = res * 10 + c - '0';
				c = readByte();
			} while (!isSpaceChar(c));
			return (minus) ? -res : res;
		}

		public long nextLong() {
			if (!hasNext())
				throw new NoSuchElementException();
			int c = readByte();
			while (isSpaceChar(c))
				c = readByte();
			boolean minus = false;
			if (c == '-') {
				minus = true;
				c = readByte();
			}
			long res = 0;
			do {
				if (c < '0' || c > '9')
					throw new InputMismatchException();
				res = res * 10 + c - '0';
				c = readByte();
			} while (!isSpaceChar(c));
			return (minus) ? -res : res;
		}

		public double nextDouble() {
			return Double.parseDouble(next());
		}

		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for (int i = 0; i < n; i++)
				a[i] = nextInt();
			return a;
		}

		public long[] nextLongArray(int n) {
			long[] a = new long[n];
			for (int i = 0; i < n; i++)
				a[i] = nextLong();
			return a;
		}

		public char[][] nextCharMap(int n, int m) {
			char[][] map = new char[n][m];
			for (int i = 0; i < n; i++)
				map[i] = next().toCharArray();
			return map;
		}
	}

	static void tr(Object... o) {
		out.println(Arrays.deepToString(o));
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.FilterInputStream;
import java.io.BufferedInputStream;
import java.util.Random;
import java.util.Comparator;
import java.io.InputStream;

/**
 * @author khokharnikunj8
 */

public class Main {
    public static void main(String[] args) {
        new Thread(null, new Runnable() {
            public void run() {
                new Main().solve();
            }
        }, "1", 1 << 26).start();
    }

    void solve() {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = in.scanInt();
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        int[][] dp;
        int[] cur;

        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            int m = in.scanInt();
            int[][] ar = new int[n][m];
            int[][] max = new int[m][2];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) ar[i][j] = in.scanInt();
            }

            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    max[i][0] = Math.max(max[i][0], ar[j][i]);
                }
                max[i][1] = i;
            }
            CodeHash.shuffle(max);
            Arrays.sort(max, new Comparator<int[]>() {

                public int compare(int[] o1, int[] o2) {
                    return -o1[0] + o2[0];
                }
            });
            dp = new int[2][1 << n];
            cur = new int[1 << n];
            for (int i = 0; i < Math.min(m, n); i++) {
                Arrays.fill(cur, 0);
                Arrays.fill(dp[i & 1], 0);
                for (int j = 0; j < 1 << n; j++) {
                    for (int k = 0; k < n; k++) {
                        int sum = 0;
                        for (int l = 0; l < n; l++) {
                            if ((j & (1 << l)) != 0) {
                                sum += (ar[(k + l) % n][max[i][1]]);
                            }
                        }
                        cur[j] = Math.max(cur[j], sum);
                    }
                }
                for (int j = 0; j < (1 << n); j++) {
                    for (int k = j; ; k = (k - 1) & j) {
                        dp[i & 1][j] = Math.max(dp[i & 1][j], dp[(i - 1) & 1][k] + cur[j ^ k]);
                        if (k == 0) break;
                    }
                }
            }
            out.println(dp[Math.min(n, m) & 1 ^ 1][(1 << n) - 1]);
        }

    }

    static class CodeHash {
        public static void shuffle(int[][] ar) {
            Random rd = new Random(new Random().nextInt());
            for (int i = 0; i < ar.length; i++) {
                int index = rd.nextInt(ar.length);
                int[] temp = ar[i];
                ar[i] = ar[index];
                ar[index] = temp;
            }
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int index;
        private BufferedInputStream in;
        private int total;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (index >= total) {
                index = 0;
                try {
                    total = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (total <= 0) return -1;
            }
            return buf[index++];
        }

        public int scanInt() {
            int integer = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    integer *= 10;
                    integer += n - '0';
                    n = scan();
                }
            }
            return neg * integer;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main {
	static final long MOD = 998244353;
	//static final long MOD = 1000000007;
	static boolean[] visited;
    public static void main(String[] args) throws IOException {
        FastScanner sc = new FastScanner();
        int Q = sc.nextInt();
        for (int q = 0; q < Q; q++) {
        	int N = sc.nextInt();
        	int M = sc.nextInt();
        	int[][] grid = new int[N][M];
        	int[][] maxes = new int[M][2];
        	for (int i = 0; i < M; i++)
        		maxes[i][1] = i;
        	for (int i = 0; i < N; i++) {
        		for (int j = 0; j < M; j++) {
        			grid[i][j] = sc.nextInt();
        			maxes[j][0] = Math.max(maxes[j][0],grid[i][j]);
        		}
        	}
        	maxes = sort(maxes);
        	int[] keyCols = new int[Math.min(M, N)];
        	for (int i = 0; i < keyCols.length; i++)
        		keyCols[i] = maxes[i][1];

        	int ans = 0;
        	for (int x = 0; x < (int)Math.pow(N,N); x++) {
        		int[] base = baseN(keyCols.length,x);
        		int ansx = 0;
        		for (int i = 0; i < N; i++) {
            		int r = 0;
            		for (int j = 0; j < keyCols.length; j++) {
            			r = Math.max(r,grid[(i+base[j])%N][keyCols[j]]);
            		}
            		ansx += r;
        		}
        		ans = Math.max(ans,ansx);
        	}
        	System.out.println(ans);
        }
    }

    public static int[] baseN(int N, int num) {
    	int[] ans = new int[N];
    	for (int i = N-1; i >= 0; i--) {
    		int pow = (int)Math.pow(N,i);
    		ans[i] = num/pow;
    		num -= ans[i]*pow;
    	}
    	return ans;
    }

    public static int[][] sort(int[][] array) {
    	//Sort an array (immune to quicksort TLE)
		Random rgen = new Random();
		for (int i = 0; i< array.length; i++) {
		    int randomPosition = rgen.nextInt(array.length);
		    int[] temp = array[i];
		    array[i] = array[randomPosition];
		    array[randomPosition] = temp;
		}
		Arrays.sort(array, new Comparator<int[]>() {
			  @Override
			  public int compare(int[] arr1, int[] arr2) {
				  //Descending order
				  return arr2[0]-arr1[0];
			  }
		});
		return array;
	}

    static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException  e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}


import java.io.*;
import java.util.*;
import static java.lang.Math.*;

public class E {
    public static void main(String[] args) throws Exception {
        new Thread(null ,new Runnable(){
            public void run(){
                try{solveIt();} catch(Exception e){e.printStackTrace(); System.exit(1);}
            }
        },"Main",1<<28).start();
    }

    static int dp[][], a[][], rows, cols;

    public static void solveIt() throws Exception {
        FastReader in = new FastReader(System.in);
        PrintWriter pw = new PrintWriter(System.out);
        int test = in.nextInt();
        for (int t = 1; t <= test; t++) {
            rows = in.nextInt();
            cols = in.nextInt();
            dp = new int[cols][1 << rows];
            for (int x[] : dp) Arrays.fill(x, -1);
            a = new int[cols][rows];
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    a[j][i] = in.nextInt();
                }
            }
            debug(a);
            pw.println(solve(0, 0));
        }

        pw.close();
    }

    static int solve(int pos, int mask) {
        if (pos >= cols) return 0;
        if (dp[pos][mask] != -1) return dp[pos][mask];
        int res = 0;
        for (int i = 0; i < rows; i++) {
            for (int k = 0; k < (1 << rows); k++) {
                if ((mask & k) != 0) continue;
                int sum = 0;
                for (int bit = 0; bit < rows; bit++) {
                    if (check(k, bit)) sum += a[pos][bit];
                }
                res = max(res, sum + solve(pos + 1, mask | k));
            }
            cyclicShift(pos);
        }
        return dp[pos][mask] = res;
    }

    static boolean check(int N, int pos) {
        return (N & (1 << pos)) != 0;
    }

    static void cyclicShift(int col) {
        int m = a[col].length;
        int last = a[col][m - 1];
        for (int i = m - 1; i >= 1; i--) {
            a[col][i] = a[col][i - 1];
        }
        a[col][0] = last;
    }

    static void debug(Object... obj) {
        System.err.println(Arrays.deepToString(obj));
    }

    static class FastReader {
        InputStream is;
        private byte[] inbuf = new byte[1024];
        private int lenbuf = 0, ptrbuf = 0;

        public FastReader(InputStream is) {
            this.is = is;
        }

        public int readByte() {
            if (lenbuf == -1) throw new InputMismatchException();
            if (ptrbuf >= lenbuf) {
                ptrbuf = 0;
                try {
                    lenbuf = is.read(inbuf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (lenbuf <= 0) return -1;
            }
            return inbuf[ptrbuf++];
        }

        public boolean isSpaceChar(int c) {
            return !(c >= 33 && c <= 126);
        }

        private boolean isEndOfLine(int c) {
            return c == '\n' || c == '\r' || c == -1;
        }

        public int skip() {
            int b;
            while ((b = readByte()) != -1 && isSpaceChar(b)) ;
            return b;
        }

        public String next() {
            int b = skip();
            StringBuilder sb = new StringBuilder();
            while (!(isSpaceChar(b))) {
                sb.appendCodePoint(b);
                b = readByte();
            }
            return sb.toString();
        }

        public String nextLine() {
            int c = skip();
            StringBuilder sb = new StringBuilder();
            while (!isEndOfLine(c)) {
                sb.appendCodePoint(c);
                c = readByte();
            }
            return sb.toString();
        }

        public int nextInt() {
            int num = 0, b;
            boolean minus = false;
            while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')) ;
            if (b == '-') {
                minus = true;
                b = readByte();
            }
            while (true) {
                if (b >= '0' && b <= '9') {
                    num = (num << 3) + (num << 1) + (b - '0');
                } else {
                    return minus ? -num : num;
                }
                b = readByte();
            }
        }

        public long nextLong() {
            long num = 0;
            int b;
            boolean minus = false;
            while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')) ;
            if (b == '-') {
                minus = true;
                b = readByte();
            }

            while (true) {
                if (b >= '0' && b <= '9') {
                    num = (num << 3) + (num << 1) + (b - '0');
                } else {
                    return minus ? -num : num;
                }
                b = readByte();
            }
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public char[] next(int n) {
            char[] buf = new char[n];
            int b = skip(), p = 0;
            while (p < n && !(isSpaceChar(b))) {
                buf[p++] = (char) b;
                b = readByte();
            }
            return n == p ? buf : Arrays.copyOf(buf, p);
        }

        public char readChar() {
            return (char) skip();
        }
    }
}


import java.util.*;
import java.io.*;

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		int q=in.nextInt();
		for(int i=0;i<q;i++) {
			out.println(work());
		}
		out.flush();
	}
	long mod=1000000007;
	long gcd(long a,long b) {
		return b==0?a:gcd(b,a%b);
	}
	int id[];
	long work() {
		int n=in.nextInt();
		int m=in.nextInt();
		long ret=0;
		PriorityQueue<int[]> pq=new PriorityQueue<>(new Comparator<int[]>() {
			public int compare(int[] arr1,int[] arr2) {
				return arr1[2]-arr2[2];
			}
		});
		long sum=0;
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				int v=in.nextInt();
				pq.add(new int[] {i,j,v});
				sum+=v;
				if(pq.size()>6)pq.poll();
			}
		}
		if(m==1)return sum;
		if(n<=3) {
			while(pq.size()>0) {
				int[] p=pq.poll();
				if(pq.size()<n) {
					ret+=p[2];
				}
			}
			return ret;
		}
		int[][] A=new int[6][];
		for(int i=0;pq.size()>0;i++) {
			A[i]=pq.poll();
		}

		for(int i=0;i<6;i++) {
			for(int j=i+1;j<6;j++) {
				for(int k=j+1;k<6;k++) {
					out:
					for(int p=k+1;p<6;p++) {
						int s=A[i][2]+A[j][2]+A[k][2]+A[p][2];
						HashMap<Integer,ArrayList<Integer>> map=new HashMap<>();
						if(map.get(A[i][1])==null) {
							map.put(A[i][1],new ArrayList<>());
						}
						if(map.get(A[j][1])==null) {
							map.put(A[j][1],new ArrayList<>());
						}
						if(map.get(A[k][1])==null) {
							map.put(A[k][1],new ArrayList<>());
						}
						if(map.get(A[p][1])==null) {
							map.put(A[p][1],new ArrayList<>());
						}
						map.get(A[i][1]).add(A[i][0]);
						map.get(A[j][1]).add(A[j][0]);
						map.get(A[k][1]).add(A[k][0]);
						map.get(A[p][1]).add(A[p][0]);
						if(map.size()!=2) {
							ret=Math.max(ret, s);
							continue;
						}
						Integer l1=null,l2=null,r1=null,r2=null;
						for(int key:map.keySet()) {
							ArrayList<Integer> list=map.get(key);
							if(map.get(key).size()!=2) {
								ret=Math.max(ret, s);
								continue out;
							}
							if(l1==null) {
								l1=list.get(0);
								l2=list.get(1);
							}else {
								r1=list.get(0);
								r2=list.get(1);
							}
						}
						if((Math.abs(l1-l2)==2&&Math.abs(r1-r2)==2)||(Math.abs(l1-l2)!=2&&Math.abs(r1-r2)!=2)) {
							ret=Math.max(ret, s);
						}
					}
				}
			}
		}

		return ret;
	}
}

class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

	public String next()
	{
		if(st==null || !st.hasMoreElements())
		{
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return st.nextToken();
	}

	public int nextInt()
	{
		return Integer.parseInt(next());
	}

	public long nextLong()
	{
		return Long.parseLong(next());
	}
}


import java.io.*;
import java.util.*;

public class E implements Runnable {
	FastReader scn;
	PrintWriter out;
	String INPUT = "";

	void solve() {
		int t = scn.nextInt();
		while(t-- > 0) {
			int n = scn.nextInt(), m = scn.nextInt();
			int[][] arr = scn.next2DInt(n, m);

			int[][] col = new int[m][2];
			for(int j = 0; j < m; j++) {
				int max = 0;
				for(int i = 0; i < n; i++) {
					max = Math.max(max, arr[i][j]);
				}
				col[j][0] = max;
				col[j][1] = j;
			}
			Arrays.parallelSort(col, (o1, o2) -> o2[0] - o1[0]);

			m = Math.min(n, m);

			int[][] lol = new int[n][m];

			for(int j = 0; j < m; j++) {
				for(int i = 0; i < n; i++) {
					lol[i][j] = arr[i][col[j][1]];
				}
			}

			int[] row = new int[n];
			for(int i = 0; i < n; i++) {
				row[i] = lol[i][0];
			}

			ans = 0;
			func(lol, 1, row);
			out.println(ans);
		}
	}

	int ans;

	void func(int[][] arr, int col, int[] rowM) {
		int n = arr.length, m = arr[0].length;
		if(col >= m) {
			int rv = 0;
			for(int a : rowM) {
				rv += a;
			}
			ans = Math.max(ans, rv);
			return;
		}

		int max = 0, ind = -1;
		for(int i = 0; i < n; i++) {
			if(arr[i][col] > max) {
				max = arr[i][col];
				ind = i;
			}
		}

		boolean in = false;
		for(int r = 0; r < n; r++) {
			if(max <= rowM[r]) {
				continue;
			}
			int rot = (ind - r + n) % n;
			int[] need = new int[n], copy = Arrays.copyOf(rowM, n);
			for(int i = 0; i < n; i++) {
				need[i] = arr[(i + rot) % n][col];
			}
			for(int i = 0; i < n; i++) {
				arr[i][col] = need[i];
				copy[i] = Math.max(rowM[i], arr[i][col]);
			}

			ind = r;
			in = true;
			func(arr, col + 1, copy);
		}

		if(!in) {
			func(arr, col + 2, rowM);
		}
	}

	public void run() {
		long time = System.currentTimeMillis();
		boolean oj = System.getProperty("ONLINE_JUDGE") != null;
		out = new PrintWriter(System.out);
		scn = new FastReader(oj);
		solve();
		out.flush();
		if (!oj) {
			System.out.println(Arrays.deepToString(new Object[] { System.currentTimeMillis() - time + " ms" }));
		}
	}

	public static void main(String[] args) {
		new Thread(null, new E(), "Main", 1 << 26).start();
	}

	class FastReader {
		InputStream is;

		public FastReader(boolean onlineJudge) {
			is = onlineJudge ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		}

		byte[] inbuf = new byte[1024];
		public int lenbuf = 0, ptrbuf = 0;

		int readByte() {
			if (lenbuf == -1)
				throw new InputMismatchException();
			if (ptrbuf >= lenbuf) {
				ptrbuf = 0;
				try {
					lenbuf = is.read(inbuf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (lenbuf <= 0)
					return -1;
			}
			return inbuf[ptrbuf++];
		}

		boolean isSpaceChar(int c) {
			return !(c >= 33 && c <= 126);
		}

		int skip() {
			int b;
			while ((b = readByte()) != -1 && isSpaceChar(b))
				;
			return b;
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		char nextChar() {
			return (char) skip();
		}

		String next() {
			int b = skip();
			StringBuilder sb = new StringBuilder();
			while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != ' ')
				sb.appendCodePoint(b);
				b = readByte();
			}
			return sb.toString();
		}

		String nextLine() {
			int b = skip();
			StringBuilder sb = new StringBuilder();
			while ((!isSpaceChar(b) || b == ' ')) { // when nextLine, (isSpaceChar(b) && b != ' ')
				sb.appendCodePoint(b);
				b = readByte();
			}
			return sb.toString();
		}

		char[] next(int n) {
			char[] buf = new char[n];
			int b = skip(), p = 0;
			while (p < n && !(isSpaceChar(b))) {
				buf[p++] = (char) b;
				b = readByte();
			}
			return n == p ? buf : Arrays.copyOf(buf, p);
		}

		int nextInt() {
			int num = 0, b;
			boolean minus = false;
			while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
				;
			if (b == '-') {
				minus = true;
				b = readByte();
			}

			while (true) {
				if (b >= '0' && b <= '9') {
					num = num * 10 + (b - '0');
				} else {
					return minus ? -num : num;
				}
				b = readByte();
			}
		}

		long nextLong() {
			long num = 0;
			int b;
			boolean minus = false;
			while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
				;
			if (b == '-') {
				minus = true;
				b = readByte();
			}

			while (true) {
				if (b >= '0' && b <= '9') {
					num = num * 10 + (b - '0');
				} else {
					return minus ? -num : num;
				}
				b = readByte();
			}
		}

		char[][] nextMatrix(int n, int m) {
			char[][] map = new char[n][];
			for (int i = 0; i < n; i++)
				map[i] = next(m);
			return map;
		}

		int[] nextIntArray(int n) {
			int[] a = new int[n];
			for (int i = 0; i < n; i++)
				a[i] = nextInt();
			return a;
		}

		long[] nextLongArray(int n) {
			long[] a = new long[n];
			for (int i = 0; i < n; i++)
				a[i] = nextLong();
			return a;
		}

		int[][] next2DInt(int n, int m) {
			int[][] arr = new int[n][];
			for (int i = 0; i < n; i++) {
				arr[i] = nextIntArray(m);
			}
			return arr;
		}

		long[][] next2DLong(int n, int m) {
			long[][] arr = new long[n][];
			for (int i = 0; i < n; i++) {
				arr[i] = nextLongArray(m);
			}
			return arr;
		}

		int[] shuffle(int[] arr) {
			Random r = new Random();
			for (int i = 1, j; i < arr.length; i++) {
				j = r.nextInt(i);
				int c = arr[i];
				arr[i] = arr[j];
				arr[j] = c;
			}
			return arr;
		}

		long[] shuffle(long[] arr) {
			Random r = new Random();
			for (int i = 1, j; i < arr.length; i++) {
				j = r.nextInt(i);
				long c = arr[i];
				arr[i] = arr[j];
				arr[j] = c;
			}
			return arr;
		}

		int[] uniq(int[] arr) {
			arr = scn.shuffle(arr);
			Arrays.sort(arr);
			int[] rv = new int[arr.length];
			int pos = 0;
			rv[pos++] = arr[0];
			for (int i = 1; i < arr.length; i++) {
				if (arr[i] != arr[i - 1]) {
					rv[pos++] = arr[i];
				}
			}
			return Arrays.copyOf(rv, pos);
		}

		long[] uniq(long[] arr) {
			arr = scn.shuffle(arr);
			Arrays.sort(arr);
			long[] rv = new long[arr.length];
			int pos = 0;
			rv[pos++] = arr[0];
			for (int i = 1; i < arr.length; i++) {
				if (arr[i] != arr[i - 1]) {
					rv[pos++] = arr[i];
				}
			}
			return Arrays.copyOf(rv, pos);
		}

		int[] reverse(int[] arr) {
			int l = 0, r = arr.length - 1;
			while (l < r) {
				arr[l] = arr[l] ^ arr[r];
				arr[r] = arr[l] ^ arr[r];
				arr[l] = arr[l] ^ arr[r];
				l++;
				r--;
			}
			return arr;
		}

		long[] reverse(long[] arr) {
			int l = 0, r = arr.length - 1;
			while (l < r) {
				arr[l] = arr[l] ^ arr[r];
				arr[r] = arr[l] ^ arr[r];
				arr[l] = arr[l] ^ arr[r];
				l++;
				r--;
			}
			return arr;
		}

		int[] compress(int[] arr) {
			int n = arr.length;
			int[] rv = Arrays.copyOf(arr, n);
			rv = uniq(rv);
			for (int i = 0; i < n; i++) {
				arr[i] = Arrays.binarySearch(rv, arr[i]);
			}
			return arr;
		}

		long[] compress(long[] arr) {
			int n = arr.length;
			long[] rv = Arrays.copyOf(arr, n);
			rv = uniq(rv);
			for (int i = 0; i < n; i++) {
				arr[i] = Arrays.binarySearch(rv, arr[i]);
			}
			return arr;
		}
	}
}


import java.io.*;
import java.util.*;

public class C {

	static int n, m, a[][];
	static int[][] memo;
	static Integer[] indices;

	static int[] getCol(int col, int shift) {
		int[] ans = new int[n];
		for (int i = 0, j = shift; i < n; i++, j = (j + 1) % n) {
			ans[i] = a[j][col];
		}
		return ans;

	}

	static int dp(int col, int msk) {
		if (col == n||col==m)
			return 0;
		if (memo[msk][col] != -1)
			return memo[msk][col];
		int ans = 0;
		for (int shift = 0; shift < n; shift++) {
			int[] currCol = getCol(indices[col], shift);
			for (int nxtMsk = 0; nxtMsk < 1 << n; nxtMsk++) {
				if ((nxtMsk & msk) != msk)
					continue;
				int curr = 0;
				int diff = msk ^ nxtMsk;
				for (int i = 0; i < n; i++)
					if ((diff & 1 << i) != 0)
						curr += currCol[i];
				ans = Math.max(ans, dp(col + 1, nxtMsk) + curr);
			}
		}
		return memo[msk][col] = ans;
	}

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner();
		PrintWriter out = new PrintWriter(System.out);
		int tc = sc.nextInt();
		while (tc-- > 0) {
			n = sc.nextInt();
			m = sc.nextInt();
			indices = new Integer[m];

			memo = new int[1 << n][m];
			for (int[] x : memo)
				Arrays.fill(x, -1);
			a = new int[n][m];
			int[] max = new int[m];
			for (int i = 0; i < n; i++)
				for (int j = 0; j < m; j++) {
					a[i][j] = sc.nextInt();
					max[j] = Math.max(max[j], a[i][j]);
				}
			for (int j = 0; j < m; j++) {
				indices[j] = j;
			}
			Arrays.sort(indices, Comparator.comparingInt(i -> -max[i]));
			out.println(dp(0, 0));
		}
		out.close();

	}

	static class Scanner {
		BufferedReader br;
		StringTokenizer st;

		Scanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		Scanner(String fileName) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(fileName));
		}

		String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		String nextLine() throws IOException {
			return br.readLine();
		}

		int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		long nextLong() throws NumberFormatException, IOException {
			return Long.parseLong(next());
		}

		double nextDouble() throws NumberFormatException, IOException {
			return Double.parseDouble(next());
		}

		boolean ready() throws IOException {
			return br.ready();
		}

	}

	static void sort(int[] a) {
		shuffle(a);
		Arrays.sort(a);
	}

	static void shuffle(int[] a) {
		int n = a.length;
		Random rand = new Random();
		for (int i = 0; i < n; i++) {
			int tmpIdx = rand.nextInt(n);
			int tmp = a[i];
			a[i] = a[tmpIdx];
			a[tmpIdx] = tmp;
		}
	}

}


import java.io.*;
import java.util.*;

public class TaskE {

    static int[][] transpose(int[][] a, int n, int m) {
        int[][] t = new int[m][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                t[j][i] = a[i][j];
            }
        }

        return t;
    }

    public static void main(String[] args) {
        FastReader in = new FastReader(System.in);
//        FastReader in = new FastReader(new FileInputStream("input.txt"));
        PrintWriter out = new PrintWriter(System.out);
//        PrintWriter out = new PrintWriter(new FileOutputStream("output.txt"));

        int t = in.nextInt();

        while (t-- > 0) {
            int n = in.nextInt();
            int m = in.nextInt();

            int[][] a = new int[n + 1][m];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    a[i][j] = in.nextInt();
                    a[n][j] = Math.max(a[n][j], a[i][j]);
                }
            }

            a = transpose(a, n, m);

            Arrays.sort(a, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    int max1 = 0;
                    for (int i = 0; i < o1.length; i++) {
                        max1 = Math.max(max1, o1[i]);
                    }

                    int max2 = 0;
                    for (int i = 0; i < o2.length; i++) {
                        max2 = Math.max(max2, o2[i]);
                    }

                    return max2 - max1;
                }
            });

            a = transpose(a, m, n);

            int[] dp = new int[1 << n];

            for (int i = 0; i < Math.min(n, m); i++) {
                int[] best = new int[1 << n];

                for (int j = 1; j < (1 << n); j++) {
                    for (int k = 0; k < n; k++) {
                        int sum = 0;
                        for (int l = 0; l < n; l++) {
                            if ((j & (1 << l)) != 0)
                                sum += a[(l + k) % n][i];
                        }
                        best[j] = Math.max(best[j], sum);
                    }
                }

                int[] dp1 = dp.clone();

                for (int j = 0; j < (1 << n); j++) {
                    for (int k = j; k > 0; k = (k - 1) & j) {
                        dp[j] = Math.max(dp[j], dp1[k ^ j] + best[k]);
                    }
                }
            }

            out.println(dp[(1 << n) - 1]);
        }

        out.close();
    }

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader(InputStream is) {
            br = new BufferedReader(new InputStreamReader(is));
        }

        Integer nextInt() {
            return Integer.parseInt(next());
        }

        Long nextLong() {
            return Long.parseLong(next());
        }

        Double nextDouble() {
            return Double.parseDouble(next());
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                st = new StringTokenizer(nextLine());
            }
            return st.nextToken();
        }

        String nextLine() {
            String s = "";
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s;
        }
    }
}