#include <bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 5e5 + 5;
const int M = 1e6 * 2 + 5;
using ll = long long;
using std::vector;

int n, m, col[N];
int vcnt[N], ecnt[N];
int to[M];
vector<int> g[N];

namespace cut_edge {
  int uf[N];
  int find(int x) {
    return x == uf[x] ? x : uf[x] = find(uf[x]);
  }

  vector<int> get() {
    vector<int> ret;
    for (int i = 1; i <= m; i++) {
      for (int j = 1; j <= n; j++)
        uf[j] = j;
      
      for (int j = 1; j <= m; j++) if (i != j) {
        int u = to[j * 2 - 1];
        int v = to[j * 2];
        uf[find(u)] = find(v);
      }

      bool fl = 0;
      for (int j = 1; j < n && !fl; j++)
        if (find(j) != find(n)) fl = 1;
      
      if (fl) ret.push_back(i);
    }

    return ret;
  }
}

namespace converter {
  vector<int> t[N];
  int uf[N];
  int find(int x) {
    return x == uf[x] ? x : uf[x] = find(uf[x]);
  }

  void convert() {
    auto ce = cut_edge::get();
    auto pos = ce.begin();
    for (int i = 1; i <= n; i++) uf[i] = i;

    for (int i = 1; i <= m; i++) {
      if (pos != ce.end() && *pos == i) {
        ++pos;
        continue;
      }

      int u = to[i * 2 - 1];
      int v = to[i * 2];
      uf[find(u)] = find(v);
    }

    int nn = 0;
    for (int i = 1; i <= n; i++) find(i);
    for (int i = 1; i <= n; i++)
      if (i == find(i)) col[i] = ++nn;
    for (int i = 1; i <= n; i++) {
      if (!col[i]) col[i] = col[find(i)];
      ++vcnt[col[i]];
    }
    
    for (int i = 1; i <= m; i++) {
      int u = to[i * 2 - 1];
      int v = to[i * 2];
      if (col[u] != col[v]) {
        u = col[u], v = col[v];
        t[u].push_back(v);
        t[v].push_back(u);
      } else {
        ++ecnt[col[u]];
      }
    }

    n = nn;
    for (int i = 1; i <= n; i++)
      g[i] = t[i];
  }
}

const int sN = 5005;
using poly = vector<ll>;

// ll f[3][sN][sN], ft[sN];
poly f[2][sN];
ll pw2[M];
int siz[N];

inline poly operator + (poly l, const poly& r) {
  if (r.size() > l.size()) l.resize(r.size());
  for (int i = 0; i < (int)std::min(l.size(), r.size()); i++)
    (l[i] += r[i]) %= mod;
  return l;
}
inline poly operator * (poly l, poly r) {
  poly x(l.size() + r.size() - 1);
  for (int i = 0; i < (int)l.size(); i++)
    for (int j = 0; j < (int)r.size(); j++)
      (x[i + j] += (l[i] * r[j]) % mod) %= mod;
  return x;
}
inline poly mulx(poly x) {
  x.insert(x.begin(), 0);
  return x;
}

void solve(int x, int fa) {
  ll V = pw2[vcnt[x]] - 1;
  f[1][x].push_back(V);
  siz[x] = 1;

  for (auto y : g[x]) if (y != fa) {
    solve(y, x);

    poly ft = (f[0][x] + f[1][x])
            * (f[0][y] + f[1][y]);
    f[1][x] = f[1][x] + mulx(ft);
    f[0][x] = f[0][x] + mulx(f[1][y] + f[0][y]);

    siz[x] += siz[y];

    // printf("[%d] %d %d\n", siz[x], (int)f[0][x].size(), (int)f[1][x].size());
  }
}

signed main() {
  freopen("barrack.in", "r", stdin);
  freopen("barrack.out", "w", stdout);

  scanf("%d%d", &n, &m);
  
  pw2[0] = 1;
  for (int i = 1; i <= m + n; i++)
    pw2[i] = pw2[i - 1] * 2 % mod;
  
  bool flag = 1;
  for (int u, v, i = 1; i <= m; i++) {
    scanf("%d%d", &u, &v);
    g[u].push_back(i * 2 - 1), to[i * 2 - 1] = v;
    g[v].push_back(i * 2), to[i * 2] = u;
    if (!((i == u && i + 1 == v) || (i + 1 == u && i == v))) flag = false;
  }

  if (flag && n == m + 1) {
    ll ans = n * pw2[n - 1] % mod;
    for (int l = 1; l < n; l++) {
      (ans += (n - l) * pw2[l - 1] % mod * pw2[n - 1 - l] % mod) %= mod;
    }
    printf("%lld\n", ans);
    return 0;
  }

  converter::convert();

  // for (int i  = 1; i <= n; i++) {
  //   printf("- %d %d\n", vcnt[i], ecnt[i]);
  //   for (auto j : g[i]) printf("%d ", j);
  //   puts("");
  // }
  // puts("-----------------------");

  solve(1, 0);
  poly fx;
  for (int i = 1; i <= n; i++)
    fx = fx + f[1][i];
  // puts("");
  
  ll ans = 0;
  for (int i = 0; i < n; i++) {
    (ans += fx[i] * pw2[m - i] % mod) %= mod;
  }
  printf("%lld\n", (ans + mod) % mod);
  return 0; 
}