#include <iostream>
#include <vector>
#include <stack>
using namespace std;
template<typename T>
inline T mymin(const T& a, const T& b) {
    return a < b ?a:b;
}
template<typename T>
inline T mymax(const T& a, const T& b) {
    return a < b ?b:a;
}
const int MAXN = 500000 + 5;
const long long MOD = 1000000007;
long long qpow(long long a, long long p) {
    long long ans = 1, base = a;
    while (p) {
        if (p&1){
            ans *= base;
            ans %= MOD;
        }
        base *= base;
        base %= MOD;
        p>>=1;
    }
    return ans;
}
// 一眼 tarjan ，结果割边忘了咋求推了十分钟
/*
    如果一个点是割而且不是根，那通向它的就是割边
    和根连着的一定是割？不一定
    根是割，那么son 当中肯定有两个点是割，它们都算就是了，根不用
    根不是割，要么一个 s 是，要么就

    算了，缩点成树，树上 dp over
*/
vector<int> oriG[MAXN];
vector<int> newG[MAXN];
vector<int> newNode[MAXN];
int toNewNode[MAXN];
int cntNode;
namespace Tarjan {
    int dfn[MAXN], low[MAXN],cnt;
    stack<int> st;
    void tarjan(int x, int fa){
        dfn[x] = low[x] = ++cnt;
        st.push(x);
        for (auto to : oriG[x]) {
            if(to != fa){
                if (!dfn[to]) {
                    tarjan(to, x);
                    low[x] = mymin(low[x],low[to]);
                } else {
                    low[x] = mymin(low[x], dfn[to]);
                }
            }
        }
        if (low[x] == dfn[x]){
            ++cntNode;
            int ins;
            do {
                ins = st.top();
                st.pop();
                newNode[cntNode].push_back(ins);
                toNewNode[ins]=cntNode;
            } while (ins != x);
            #ifdef MYDEBUG
            cout << "At cnt=" << cntNode << "\n   ";
            for (auto x: newNode[cntNode]) {
                cout<< " " << x;
            }
            cout << '\n';
            #endif // MYDEBUG
        }
    }
    int vis[MAXN];
    void buildNewG(int x){
        #ifdef MYDEBUG
        cout << x << ":\n";
        #endif // MYDEBUG
        vis[x] = true;
        for (int oriN : newNode[x]){
            for (int toN: oriG[oriN]){
                auto to = toNewNode[toN];
                if (!vis[to]) {
                    newG[x].push_back(to);
                    #ifdef MYDEBUG
                    cout << "    " << x << " " << to << "\n";
                    #endif // MYDEBUG
                    buildNewG(to);
                }
            }
        }
    }
}
long long dp[MAXN][2]; // valid, allUnvalid
int dfs(int x, int fa) {
    bool isleaf=true;
    long long chOwn = (newNode[x].size() == 1) ? 1ll: qpow(2, newNode[x].size())
                            * ((qpow(2, newNode[x].size()) + MOD - 1) % MOD) % MOD,
              uchOwn = (newNode[x].size() == 1) ? 1ll: qpow(2, newNode[x].size());
    //dp[x][1] =dp[x][0]=1;
    long long allSon =1, uallSon=1;
    #ifdef MYDEBUG
        cout << x << ":\n" <<
            "    chOwn=" << chOwn <<"  uchOwn=" << uchOwn << '\n' ;
    #endif // MYDEBUG
    for (auto to: newG[x]){
        if (to != fa) {
            isleaf= false;
            dfs(to, x);
            long long chSon = dp[to][0],
                      uchSon = dp[to][1];
            #ifdef MYDEBUG
                cout << x << "  " << to << ":\n"
                    << "    chSon=" << chSon << "  uchSon=" << uchSon << '\n' ;
            #endif // MYDEBUG
            dp[x][0] += chOwn* uchSon % MOD + uchOwn * chSon ; // 不修
            dp[x][0] += chOwn * chSon % MOD + chOwn * uchSon % MOD + chSon * uchOwn % MOD; // 修了
            dp[x][0] %= MOD;
            dp[x][1] += uchOwn * uchSon;
            dp[x][1] %= MOD;
        }
    }
    if (isleaf) {
        dp[x][0] = chOwn; // choose x only
        dp[x][1] = uchOwn;
    }
}
int main()
{
    freopen("barrack.in", "r", stdin);
    freopen("barrack.out","w",stdout);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        oriG[u].push_back(v);
        oriG[v].push_back(u);
    }
    Tarjan::tarjan(1, -1);
    #ifdef MYDEBUG
    cout << cntNode << '\n';
    #endif // MYDEBUG
    Tarjan::buildNewG(1);
    dfs(1, -1);
    cout << dp[1][0] << '\n';
    return 0;
}

