#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;
 
#define fi first
#define se second
#define mp make_pair
#define pb push_back
 
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld; 
typedef tree<ii, null_type, less<ii>, rb_tree_tag, tree_order_statistics_node_update> pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
int add(int a, int b)
{
	a+=b;
	while(a>=MOD) a-=MOD;
	return a;
}
void radd(int &a, int b)
{
	a=add(a,b); 
}
int mult(int a, int b)
{
	return (a*1LL*b)%MOD;
}
void rmult(int &a, int b)
{
	a=mult(a,b);
}
int modpow(int a, int b)
{
	int r=1;
	while(b)
	{
		if(b&1) r=mult(r,a);
		a=mult(a,a);
		b>>=1;
	}
	return r;
}
int choose(int a, int b)
{
	if(a<b) return 0;
	if(b==0) return 1;
	if(a==b) return 1;
	return mult(fact[a],mult(ifact[b],ifact[a-b]));
}
int inverse(int a)
{
	return modpow(a,MOD-2);
}
void init(int _n)
{
	fact.clear(); ifact.clear(); inv.clear(); pow2.clear();
	fact.resize(_n+1);
	ifact.resize(_n+1);
	inv.resize(_n+1);
	pow2.resize(_n+1);
	pow2[0]=1;
	ifact[0]=1;
	fact[0]=1;
	for(int i=1;i<=_n;i++)
	{
		pow2[i]=add(pow2[i-1],pow2[i-1]);
		fact[i]=mult(fact[i-1],i);
		//ifact[i]=mult(ifact[i-1],inv[i]);
	}
	ifact[_n] = inverse(fact[_n]);
	for(int i=_n-1;i>=1;i--)
	{
		ifact[i] = mult(ifact[i + 1], i + 1);
	}
	for(int i=1;i<=_n;i++)
	{
		inv[i] = mult(fact[i-1],ifact[i]);
	}
}

int ipow2[1111];

int adj[18][18];
int dp[1700000];
int reach[2][(1<<16)];
int n,m; 
int p3[18];
int cntadj[15000000];

int solve(int u, int bit)
{
	if(!(bit&(1<<u))) return 0;
	if(reach[u][bit]!=-1) return reach[u][bit];
	int res=1;
	vi V;
	for(int i=0;i<n;i++)
	{
		if(bit&(1<<i)) V.pb(i);
	}
	if(bit>0)
	{
		for(int j=bit;;j=(bit&(j-1)))
		{
			if(j==bit) continue;
			int coeff = 1;
			int bb=0;
			for(int x:V)
			{
				if(j&(1<<x)) bb+=p3[x];// VV[1].pb(x);
				else bb+=p3[x]*2;//VV[0].pb(x);
			}
			coeff=ipow2[cntadj[bb]];
			radd(res,MOD-mult(coeff,solve(u,j)));
			if(j==0) break;
		}
	}
	return (reach[u][bit]=res);
}

int V[18];
int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0);
	init(1201);
	for(int i=0;i<=1000;i++) ipow2[i]=inverse(pow2[i]);
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int u,v; cin>>u>>v; u--; v--;
		adj[u][v]=adj[v][u]=1;
	}
	p3[0]=1;
	for(int i=1;i<=17;i++) p3[i]=p3[i-1]*3;
	for(int i=0;i<2;i++)
	{
		memset(reach,-1,sizeof(reach));
		reach[i][(1<<i)]=1;
	}
	int ans=0;
	for(int i=1;i<p3[n];i++)
	{
		int cur=i;
		int exv=-1; int firstv=-1;
		for(int j=0;j<n;j++)
		{
			V[j]=cur%3; cur/=3;
			if(V[j]!=0){exv=j; firstv=V[j];}
		}
		cntadj[i]=cntadj[i-firstv*p3[exv]];
		for(int j=0;j<n;j++)
		{
			if(V[j]!=0&&V[j]!=firstv)
			{
				cntadj[i]+=adj[exv][j];
			}
		}
		//if(i%100000==0) cerr<<"FINISH "<<i<<' '<<p3[n]<<'\n';
	}
	//cerr<<"HALFWAY DONE"<<endl;
	for(int i=0;i<p3[n-2];i++)
	{
		V[0]=1;V[1]=2;
		int cur=i;
		int b2=2;
		int b1=1;
		for(int j=2;j<n;j++)
		{
			V[j]=cur%3;
			if(V[j]==1) b1|=(1<<j);
			if(V[j]==2) b2|=(1<<j);
			cur/=3;
		}
		int bb=0;
		for(int j=0;j<n;j++)
		{
			if(b1&(1<<j)) bb+=p3[j];
			if(b2&(1<<j)) bb+=2*p3[j];
		}
		if(cntadj[bb]>0) continue;
		bb=0;
		for(int j=0;j<n;j++)
		{
			if(b1&(1<<j)) bb+=p3[j];
			else if(b2&(1<<j)) bb+=p3[j];
			else bb+=2*p3[j];
		}
		/*
		for(int x:V[0])
		{
			for(int y:V[1]) cnt_edge+=adj[x][y];
			for(int y:V[2]) cnt_edge+=adj[x][y];
		}
		*/
		int cnt_edge = cntadj[bb];
		ans=add(ans,mult(pow2[m-cnt_edge],mult(solve(0,b1),solve(1,b2))));
	}
	ans=add(pow2[m],MOD-ans);
	cout<<ans<<'\n';
}


Measured memory_bytes: 59648