#include <bits/stdc++.h>
using namespace std;
const int block_size = 320;
const long long mod = 1e9 + 7;
const long long inf = 1e9 + 7;
const long double eps = 1e-9;
const double PI = atan(1) * 4;
template <typename T>
inline int sign(const T &a) {
  if (a < 0) return -1;
  if (a > 0) return 1;
  return 0;
}
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char *s) { return to_string((string)s); }
string to_string(bool b) { return (b ? "true" : "false"); }
template <typename A, typename B>
string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <typename A>
string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
template <typename T, typename S>
inline bool upmin(T &a, const S &b) {
  return a > b ? a = b, 1 : 0;
}
template <typename T, typename S>
inline bool upmax(T &a, const S &b) {
  return a < b ? a = b, 1 : 0;
}
template <typename T>
inline void in(T &x) {
  x = 0;
  T f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  x *= f;
}
unsigned long long twop(long long x) { return 1ULL << x; }
template <typename T>
T MOD(T a, T m) {
  a %= m;
  if (a < 0) a += m;
  return a;
}
template <typename T>
T inverse(T a, T m) {
  a = MOD(a, m);
  if (a <= 1) return a;
  return MOD((1 - inverse(m, a) * m) / a, m);
}
template <typename A, typename B>
inline void in(A &x, B &y) {
  in(x);
  in(y);
}
template <typename A, typename B, typename C>
inline void in(A &x, B &y, C &z) {
  in(x);
  in(y);
  in(z);
}
template <typename A, typename B, typename C, typename D>
inline void in(A &x, B &y, C &z, D &d) {
  in(x);
  in(y);
  in(z);
  in(d);
}
template <typename T>
T sqr(T x) {
  return x * x;
}
long long gcd(long long a, long long b) {
  while (b != 0) {
    a %= b;
    swap(a, b);
  }
  return abs(a);
}
long long fast(long long a, long long b, long long mod) {
  long long ans = 1;
  while (b) {
    if (b & 1) {
      b--;
      ans = ans * a % mod;
    } else {
      a = a * a % mod;
      b /= 2;
    }
  }
  return ans % mod;
}
long long ans = 0;
class Articulation {
 public:
  static const int N = 1000005;
  std::vector<pair<int, int> > keyE;
  std::vector<int> keyV, cc[N];
  int cnt;
  vector<int> BCC[N];
  int run(int n, const std::vector<int> G[]) {
    memset(dfn, use = 0, sizeof(dfn[0]) * n);
    memset(low, cnt = 0, sizeof(low[0]) * n);
    keyE.clear();
    fill_n(cc, n, keyV = std::vector<int>());
    for (int i = 0; i < n; ++i) {
      if (!dfn[i]) dfs(i, 1, G);
    }
    for (long long i = 0; i < n; i++) {
      for (auto j : cc[i]) {
        BCC[j].push_back(i);
      }
    }
    for (long long i = 0; i < N; i++) {
      if (BCC[i].size() <= 2) BCC[i].clear();
      if (((int)BCC[i].size())) {
      };
    }
    return cnt;
  }

 private:
  int dfn[N], low[N], dot[N], use;
  void dfs(int x, int dep, const std::vector<int> G[]) {
    int src = 0, out = 1 < dep;
    dot[use++] = x;
    dfn[x] = low[x] = dep;
    for (auto &y : G[x]) {
      if (!dfn[y]) {
        dfs(y, dep + 1, G);
        low[x] = std::min(low[x], low[y]);
        if (low[y] > dfn[x]) keyE.push_back(pair<int, int>(x, y));
        if (low[y] >= dfn[x]) {
          if (++out == 2) keyV.push_back(x);
          while (dot[--use] != y) cc[dot[use]].push_back(cnt);
          cc[x].push_back(cnt);
          cc[y].push_back(cnt++);
        }
      } else if (dfn[y] != dfn[x] - 1 || src++) {
        low[x] = std::min(low[x], dfn[y]);
      }
    }
  }
} biconnected;
vector<int> G[500010];
long long n, m;
void get_frac(long long c) {
  return;
  for (long long i = 0; i < 100; i++) {
    for (long long j = 1; j < 100; j++) {
      if (MOD(i - j * c, mod) == 0) {
        cerr << i << "/" << j << endl;
        return;
      }
    }
  }
  for (long long i = 0; i >= -100; i--) {
    for (long long j = 1; j < 100; j++) {
      if (MOD(i - j * c, mod) == 0) {
        cerr << i << "/" << j << endl;
        return;
      }
    }
  }
}
void calcEX() {
  long long tmp = 0;
  tmp += n * inverse(2ll, mod);
  tmp %= mod;
  tmp -= m * inverse(4ll, mod);
  tmp %= mod;
  for (long long i = 0; i < biconnected.N; i++) {
    if (biconnected.BCC[i].size()) {
      tmp += inverse(fast(2, biconnected.BCC[i].size(), mod), mod);
      tmp %= mod;
    }
  }
  tmp %= mod;
  ans -= tmp * tmp % mod;
  ans += (n * n + n) % mod * inverse(4ll, mod) % mod;
  ans += -(2 * m + n * m) % mod * inverse(4ll, mod) % mod;
  ans = MOD(ans, mod);
}
void calcNC() {
  long long tmp = 0;
  for (long long i = 0; i < biconnected.N; i++) {
    if (biconnected.BCC[i].size()) {
      tmp += biconnected.BCC[i].size() *
             inverse(fast(2, biconnected.BCC[i].size(), mod), mod) % mod;
      tmp %= mod;
      tmp += (n - biconnected.BCC[i].size()) *
             inverse(fast(2, biconnected.BCC[i].size() + 1, mod), mod) % mod;
      tmp %= mod;
    }
  }
  tmp *= 2;
  ans += tmp;
  ans %= mod;
}
void calcm2() {
  long long tot = m * m - m;
  tot %= mod;
  long long tmp = 0;
  tmp += m * inverse(4ll, mod) % mod;
  get_frac(tmp);
  for (long long i = 0; i < n; i++) {
    long long siz = ((int)G[i].size());
    long long cnt = siz * (siz - 1) % mod;
    tot -= cnt;
    tmp += cnt * inverse(8ll, mod) % mod;
  }
  tmp += tot * inverse(16ll, mod) % mod;
  get_frac(tmp);
  ans += tmp % mod;
}
void calccm() {
  long long tmp = 0;
  for (long long i = 0; i < biconnected.N; i++) {
    if (biconnected.BCC[i].size()) {
      long long tot = m;
      long long siz = biconnected.BCC[i].size();
      tot -= siz;
      tmp += fast(inverse(2ll, mod), siz, mod) * siz % mod;
      for (auto v : biconnected.BCC[i]) {
        long long cnt = ((int)G[v].size()) - 2;
        tot -= cnt;
        tmp += fast(inverse(2ll, mod), siz + 1, mod) * cnt % mod;
      }
      tmp += fast(inverse(2ll, mod), siz + 2, mod) * tot % mod;
    }
  }
  {};
  get_frac(tmp);
  ans += -2 * tmp;
  ans %= mod;
}
void calccc() {
  long long tmpans = 0;
  long long tot = 0;
  for (long long i = 0; i < biconnected.N; i++) {
    if (biconnected.BCC[i].size()) {
      tot += fast(inverse(2ll, mod), biconnected.BCC[i].size(), mod);
    }
  }
  tot %= mod;
  tmpans += tot * tot % mod;
  for (long long i = 0; i < n; i++) {
    vector<long long> sizs;
    long long tmp = 0;
    for (auto c : biconnected.cc[i]) {
      sizs.push_back(((int)biconnected.BCC[c].size()));
      if (sizs.back() != 0) {
        tmp += fast(inverse(2ll, mod), sizs.back(), mod);
      }
    }
    {};
    get_frac(tmp);
    tmp %= mod;
    tmpans += tmp * tmp % mod;
  }
  for (long long i = 0; i < biconnected.N; i++) {
    if (biconnected.BCC[i].size()) {
      long long siz = biconnected.BCC[i].size();
      tmpans += fast(inverse(2ll, mod), siz, mod) -
                (siz + 1) * fast(inverse(2ll, mod), 2 * siz, mod);
    }
  }
  {};
  get_frac(tmpans);
  ans += tmpans;
}
namespace SOLVE {
void main() {
  in(n, m);
  for (long long i = 0; i < m; i++) {
    int u, v;
    in(u, v);
    G[u - 1].push_back(v - 1);
    G[v - 1].push_back(u - 1);
  }
  biconnected.run(n, G);
  calcEX();
  calcNC();
  calcm2();
  calccm();
  calccc();
  get_frac(ans);
  cout << MOD(ans, mod) << endl;
}
}  // namespace SOLVE
signed main() {
  int t = 1;
  for (int i = 1; i <= t; i++) {
    SOLVE::main();
  }
  return 0;
}
