#include using namespace std; using ll = long long; #define all(x) begin(x), end(x) #define len(x) int((x).size()) template inline bool chmin(T &a, const T &b) { if (b < a) { a = b; return true; } else { return false; } } template inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } else { return false; } } constexpr int Mod = 1e9 + 7; inline int Red(int x) { return x - (x >= Mod) * Mod; } inline void Add(int &x, int y) { x = Red(x + y); } inline int Norm(int x) { return x + (x < 0) * Mod; } inline void Sub(int &x, int y) { x = Norm(x - y);} constexpr int N = 30, M = 240, S = (1 << 15) + 10; int n, m, f[S], g[S][2], pw[M], adj[N], ee[S]; struct Edge { int u, v, w; bool operator<(Edge x) const { return w < x.w; } } e[M]; #define popcnt __builtin_popcount #define lowbit __builtin_ctz int E(int s) { int ans = 0; for (int i = 0; i < m; ++i) { auto [u, v, _] = e[i]; ans += (s >> u & 1) == 1 && (s >> v & 1) == 1; } return 2 * ans; } struct DSU { int f[N]; void Init() { iota(all(f), 0); } int Find(int x) { while (x != f[x]) x = f[x] = f[f[x]]; return x; } bool Merge(int x, int y) { x = Find(x), y = Find(y); if (x == y) { return false; } else { f[x] = y; return true; } } } dsu; int GetMul() { int mul = 1; for (int i = 1; i <= m; ++i) mul = ll(mul) * ((Mod + 1) / 2) % Mod; mul = ll(mul) * mul % Mod; return mul; } void Dp() { memset(adj, 0, sizeof adj); for (int i = 0; i < m; ++i) { auto [u, v, w] = e[i]; adj[u] += 1 << v, adj[v] += 1 << u; } memset(f, 0, sizeof f), memset(g, 0, sizeof g); g[0][0] = 1; pw[0] = 1; for (int i = 1; i <= 2 * m; ++i) pw[i] = Red(2 * pw[i - 1]); for (int s = 1; s < (1 << n); ++s) { int r = lowbit(s), ss = s - (1 << r); for (int tt = ss;; --tt &= ss) { int t = tt + (1 << r); Sub(g[s][1], ll(f[t]) * (g[s - t][0] + g[s - t][1]) % Mod); Sub(g[s][0], ll(f[t]) * g[s - t][0] % Mod); if (tt == 0) break; } ee[s] = E(s); f[s] = pw[ee[s]]; for (int t = s; --t &= s;) { int r = lowbit(s - t); ee[t] = ee[t + (1 << r)] - popcnt(adj[r] & s); } for (int t = s; t > 0; --t &= s) { Add(f[s], ll(g[t][0]) * pw[ee[s - t]] % Mod); } Sub(g[s][1], f[s]), Sub(g[s][0], f[s]); // cerr << "f[" << s << "] = " << f[s] << "\n"; } int ans = 0; for (int s = 1; s < (1 << n); ++s) Sub(ans, ll(g[s][1]) * pw[ee[(1 << n) - 1 - s]] % Mod); cout << ll(ans) * GetMul() % Mod << "\n"; } void Proc() { cin >> n >> m; for (int i = 0; i < m; ++i) { auto &[u, v, w] = e[i]; cin >> u >> v >> w, --u, --v; } sort(e, e + m); if (e[m - 1].w == 1) { Dp(); return; } bool is_b = true; for (int i = 0; i < m - 1; ++i) is_b &= e[i].w < e[i + 1].w; int mst = 0, new_m = 0; dsu.Init(); for (int i = 0; i < m; ++i) { auto [u, v, w] = e[i]; if (dsu.Merge(u, v)) { mst += w; if (is_b) e[new_m++] = e[i]; } } if (is_b) { m = new_m; Dp(); return; } vector dmst; for (int s = 0; s < (1 << m); ++s) { if (popcnt(s) != n - 1) continue; dsu.Init(); bool ok = true; int sum = 0; for (int i = 0; i < m; ++i) { if ((s >> i & 1) == 0) continue; auto [u, v, w] = e[i]; sum += w; if (!dsu.Merge(u, v)) ok = false; } if (!ok || sum != mst) continue; static vector> adj[N]; for (int i = 0; i < n; ++i) adj[i].clear(); for (int i = 0; i < m; ++i) { auto [u, v, w] = e[i]; if ((s >> i & 1) == 1) adj[u].emplace_back(2 * i, v), adj[v].emplace_back(2 * i + 1, u); } auto dfs = [&](auto dfs, int u, int p) -> int { int s = 0; for (auto [id, v] : adj[u]) { if (v != p) s += (1 << id) + dfs(dfs, v, u); } return s; }; for (int i = 0; i < n; ++i) dmst.push_back(dfs(dfs, i, -1)); } int ans = 0; for (int s = 0; s < (1 << 2 * m); ++s) { for (int t : dmst) { if ((s | t) == s) { ++ans; break; } } } cout << ll(ans) * GetMul() % Mod << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin.exceptions(ios::failbit); int _, t; cin >> _ >> t; for (int _ = 1; _ <= t; ++_) Proc(); }