import igraph as ig
import numpy as np
import torch
def graph_to_mat(g):
    """Returns adjacency matrix of ig.Graph object """
    return np.array(g.get_adjacency().data).astype(int)

def mat_to_graph(mat):
    """Returns ig.Graph object for adjacency matrix """
    return ig.Graph.Weighted_Adjacency(mat.tolist())

def graph_to_toporder(g):
    """Returns adjacency matrix of ig.Graph object """
    return np.array(g.topological_sorting()).astype(int)

def mat_to_toporder(mat):
    """Returns adjacency matrix of ig.Graph object """
    return np.array(mat_to_graph(mat).topological_sorting()).astype(int)

def acyclic_constr_nograd(mat, n_vars):
    alpha = 1.0 / n_vars
    M = torch.eye(n_vars) + alpha * mat
    M_mult = torch.linalg.matrix_power(M, n_vars)
    h = torch.trace(M_mult) - n_vars
    return h
