// Arup Guha
// Solution to COT 3100 Program #2: Three CNF SAT
// 3/28/2017

import java.util.*;

public class threesat {

	public static int numV;
	public static int numC;
	public static int[][] clauses;

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int numCases = stdin.nextInt();

		// Process each case.
		for (int loop=0; loop<numCases; loop++) {

			// Get all the input.
			numV = stdin.nextInt();
			numC = stdin.nextInt();
			clauses = new int[numC][3];
			for (int i=0; i<numC; i++)
				for (int j=0; j<3; j++)
					clauses[i][j] = stdin.nextInt();

			// Solve and output the result.
			System.out.println(solve());
		}
	}

	public static String solve() {

		// Try each truth setting - if one works, return "yes"
		for (int mask=0; mask<(1<<numV); mask++)
			if (eval(mask))
				return "yes";

		// If we get here, none of them worked.
		return "no";
	}

	// Returns the value of the formula for the truth setting given by mask.
	public static boolean eval(int mask) {

		// Go through each clause.
		for (int i=0; i<numC; i++) {

			boolean res = false;

			// Try each variable - if any match we live to try another clause.
			for (int j=0; j<3; j++) {
				if (matches(i, j, mask)) {
					res = true;
					break;
				}
			}

			// If we get here and didn't hit a true, the clause is doomed.
			if (!res) return false;
		}

		// If we get here, we satisfied every clause.
		return true;
	}

	public static boolean matches(int clauseNum, int itemNum, int mask) {

		// Return true if this variable is set to true and it appears in this location, OR
		// if this variable is set to false and its negation appears in the this location.
		return (clauses[clauseNum][itemNum] > 0 && (((1<<(clauses[clauseNum][itemNum]-1)) & mask) > 0)) ||
			   (clauses[clauseNum][itemNum] < 0 && (((1<<(-clauses[clauseNum][itemNum]-1)) & mask) == 0));
	}
}