def parallel_graph_evaluation(data, adj_matrix, nb_runs=16,
                              nb_jobs=None, **kwargs):
    """Parallelize the various runs of CGNN to evaluate a graph."""
    nb_jobs = SETTINGS.get_default(nb_jobs=nb_jobs)
    if nb_runs == 1:
        return graph_evaluation(data, adj_matrix, **kwargs)
    else:
        output = Parallel(n_jobs=nb_jobs)(delayed(graph_evaluation)(data, adj_matrix,
                                          idx=run, gpu_id=run % SETTINGS.GPU,
                                          **kwargs) for run in range(nb_runs))
        return np.mean(output)

def parallel_graph_evaluation ( data , adj_matrix , nb_runs = 16 , nb_jobs = None , * * kwargs ) : nb_jobs = SETTINGS . get_default ( nb_jobs = nb_jobs ) if nb_runs == 1 : return graph_evaluation ( data , adj_matrix , * * kwargs ) else : output = Parallel ( n_jobs = nb_jobs ) ( delayed ( graph_evaluation ) ( data , adj_matrix , idx = run , gpu_id = run % SETTINGS . GPU , * * kwargs ) for run in range ( nb_runs ) ) return np . mean ( output )

Parallelize the various runs of CGNN to evaluate a graph .


def forward(self):
        """Generate according to the topological order of the graph."""
        self.noise.data.normal_()
        if not self.confounding:
            for i in self.topological_order:
                self.generated[i] = self.blocks[i](th.cat([v for c in [
                                                   [self.generated[j] for j in np.nonzero(self.adjacency_matrix[:, i])[0]],
                                                   [self.noise[:, [i]]]] for v in c], 1))
        else:
            for i in self.topological_order:
                self.generated[i] = self.blocks[i](th.cat([v for c in [
                                                   [self.generated[j] for j in np.nonzero(self.adjacency_matrix[:, i])[0]],
                                                   [self.corr_noise[min(i, j), max(i, j)] for j in np.nonzero(self.i_adj_matrix[:, i])[0]]
                                                   [self.noise[:, [i]]]] for v in c], 1))
        return th.cat(self.generated, 1)

def forward ( self ) : self . noise . data . normal_ ( ) if not self . confounding : for i in self . topological_order : self . generated [ i ] = self . blocks [ i ] ( th . cat ( [ v for c in [ [ self . generated [ j ] for j in np . nonzero ( self . adjacency_matrix [ : , i ] ) [ 0 ] ] , [ self . noise [ : , [ i ] ] ] ] for v in c ] , 1 ) ) else : for i in self . topological_order : self . generated [ i ] = self . blocks [ i ] ( th . cat ( [ v for c in [ [ self . generated [ j ] for j in np . nonzero ( self . adjacency_matrix [ : , i ] ) [ 0 ] ] , [ self . corr_noise [ min ( i , j ) , max ( i , j ) ] for j in np . nonzero ( self . i_adj_matrix [ : , i ] ) [ 0 ] ] [ self . noise [ : , [ i ] ] ] ] for v in c ] , 1 ) ) return th . cat ( self . generated , 1 )

Generate according to the topological order of the graph .


def run(self, data, train_epochs=1000, test_epochs=1000, verbose=None,
            idx=0, lr=0.01, **kwargs):
        """Run the CGNN on a given graph."""
        verbose = SETTINGS.get_default(verbose=verbose)
        optim = th.optim.Adam(self.parameters(), lr=lr)
        self.score.zero_()
        with trange(train_epochs + test_epochs, disable=not verbose) as t:
            for epoch in t:
                optim.zero_grad()
                generated_data = self.forward()
                mmd = self.criterion(generated_data, data)
                if not epoch % 200:
                    t.set_postfix(idx=idx, epoch=epoch, loss=mmd.item())
                mmd.backward()
                optim.step()
                if epoch >= test_epochs:
                    self.score.add_(mmd.data)

        return self.score.cpu().numpy() / test_epochs

def run ( self , data , train_epochs = 1000 , test_epochs = 1000 , verbose = None , idx = 0 , lr = 0.01 , * * kwargs ) : verbose = SETTINGS . get_default ( verbose = verbose ) optim = th . optim . Adam ( self . parameters ( ) , lr = lr ) self . score . zero_ ( ) with trange ( train_epochs + test_epochs , disable = not verbose ) as t : for epoch in t : optim . zero_grad ( ) generated_data = self . forward ( ) mmd = self . criterion ( generated_data , data ) if not epoch % 200 : t . set_postfix ( idx = idx , epoch = epoch , loss = mmd . item ( ) ) mmd . backward ( ) optim . step ( ) if epoch >= test_epochs : self . score . add_ ( mmd . data ) return self . score . cpu ( ) . numpy ( ) / test_epochs


def create_graph_from_data(self, data):
        """Use CGNN to create a graph from scratch. All the possible structures
        are tested, which leads to a super exponential complexity. It would be
        preferable to start from a graph skeleton for large graphs.

        Args:
            data (pandas.DataFrame): Observational data on which causal
               discovery has to be performed.
        Returns:
            networkx.DiGraph: Solution given by CGNN.

        """
        warnings.warn("An exhaustive search of the causal structure of CGNN without"
                      " skeleton is super-exponential in the number of variables.")

        # Building all possible candidates:
        nb_vars = len(list(data.columns))
        data = scale(data.values).astype('float32')

        candidates = [np.reshape(np.array(i), (nb_vars, nb_vars)) for i in itertools.product([0, 1], repeat=nb_vars*nb_vars)
                      if (np.trace(np.reshape(np.array(i), (nb_vars, nb_vars))) == 0
                          and nx.is_directed_acyclic_graph(nx.DiGraph(np.reshape(np.array(i), (nb_vars, nb_vars)))))]

        warnings.warn("A total of {} graphs will be evaluated.".format(len(candidates)))
        scores = [parallel_graph_evaluation(data, i, nh=self.nh, nb_runs=self.nb_runs, gpu=self.gpu,
                                            nb_jobs=self.nb_jobs, lr=self.lr, train_epochs=self.train_epochs,
                                            test_epochs=self.test_epochs, verbose=self.verbose) for i in candidates]
        final_candidate = candidates[scores.index(min(scores))]
        output = np.zeros(final_candidate.shape)

        # Retrieve the confidence score on each edge.
        for (i, j), x in np.ndenumerate(final_candidate):
            if x > 0:
                cand = final_candidate
                cand[i, j] = 0
                output[i, j] = min(scores) - scores[candidates.index(cand)]

        return nx.DiGraph(candidates[output],
                          {idx: i for idx, i in enumerate(data.columns)})

Use CGNN to create a graph from scratch . All the possible structures are tested which leads to a super exponential complexity . It would be preferable to start from a graph skeleton for large graphs .


def orient_directed_graph(self, data, dag, alg='HC'):
        """Modify and improve a directed acyclic graph solution using CGNN.

        Args:
            data (pandas.DataFrame): Observational data on which causal
               discovery has to be performed.
            dag (nx.DiGraph): Graph that provides the initial solution,
               on which the CGNN algorithm will be applied.
            alg (str): Exploration heuristic to use, among ["HC", "HCr",
               "tabu", "EHC"]
        Returns:
            networkx.DiGraph: Solution given by CGNN.

        """
        alg_dic = {'HC': hill_climbing, 'HCr': hill_climbing_with_removal,
                   'tabu': tabu_search, 'EHC': exploratory_hill_climbing}

        return alg_dic[alg](data, dag, nh=self.nh, nb_runs=self.nb_runs, gpu=self.gpu,
                            nb_jobs=self.nb_jobs, lr=self.lr, train_epochs=self.train_epochs,
                            test_epochs=self.test_epochs, verbose=self.verbose)

def orient_directed_graph ( self , data , dag , alg = 'HC' ) : alg_dic = { 'HC' : hill_climbing , 'HCr' : hill_climbing_with_removal , 'tabu' : tabu_search , 'EHC' : exploratory_hill_climbing } return alg_dic [ alg ] ( data , dag , nh = self . nh , nb_runs = self . nb_runs , gpu = self . gpu , nb_jobs = self . nb_jobs , lr = self . lr , train_epochs = self . train_epochs , test_epochs = self . test_epochs , verbose = self . verbose )

Modify and improve a directed acyclic graph solution using CGNN .


def orient_undirected_graph(self, data, umg, alg='HC'):
        """Orient the undirected graph using GNN and apply CGNN to improve the graph.

        Args:
            data (pandas.DataFrame): Observational data on which causal
               discovery has to be performed.
            umg (nx.Graph): Graph that provides the skeleton, on which the GNN
               then the CGNN algorithm will be applied.
            alg (str): Exploration heuristic to use, among ["HC", "HCr",
               "tabu", "EHC"]
        Returns:
            networkx.DiGraph: Solution given by CGNN.

        .. note::
           GNN (``cdt.causality.pairwise.GNN``) is first used to orient the
           undirected graph and output a DAG before applying CGNN.
        """
        warnings.warn("The pairwise GNN model is computed on each edge of the UMG "
                      "to initialize the model and start CGNN with a DAG")
        gnn = GNN(nh=self.nh, lr=self.lr)

        og = gnn.orient_graph(data, umg, nb_runs=self.nb_runs, nb_max_runs=self.nb_runs,
                              nb_jobs=self.nb_jobs, train_epochs=self.train_epochs,
                              test_epochs=self.test_epochs, verbose=self.verbose, gpu=self.gpu)  # Pairwise method
        # print(nx.adj_matrix(og).todense().shape)
        # print(list(og.edges()))
        dag = dagify_min_edge(og)
        # print(nx.adj_matrix(dag).todense().shape)

        return self.orient_directed_graph(data, dag, alg=alg)

Orient the undirected graph using GNN and apply CGNN to improve the graph .


def eval_entropy(x):
    """Evaluate the entropy of the input variable.

    :param x: input variable 1D
    :return: entropy of x
    """
    hx = 0.
    sx = sorted(x)
    for i, j in zip(sx[:-1], sx[1:]):
        delta = j-i
        if bool(delta):
            hx += np.log(np.abs(delta))
    hx = hx / (len(x) - 1) + psi(len(x)) - psi(1)

    return hx

def eval_entropy ( x ) : hx = 0. sx = sorted ( x ) for i , j in zip ( sx [ : - 1 ] , sx [ 1 : ] ) : delta = j - i if bool ( delta ) : hx += np . log ( np . abs ( delta ) ) hx = hx / ( len ( x ) - 1 ) + psi ( len ( x ) ) - psi ( 1 ) return hx

Evaluate the entropy of the input variable .


def integral_approx_estimator(x, y):
    """Integral approximation estimator for causal inference.

    :param x: input variable x 1D
    :param y: input variable y 1D
    :return: Return value of the IGCI model >0 if x->y otherwise if return <0
    """
    a, b = (0., 0.)
    x = np.array(x)
    y = np.array(y)
    idx, idy = (np.argsort(x), np.argsort(y))

    for x1, x2, y1, y2 in zip(x[[idx]][:-1], x[[idx]][1:], y[[idx]][:-1], y[[idx]][1:]):
        if x1 != x2 and y1 != y2:
            a = a + np.log(np.abs((y2 - y1) / (x2 - x1)))

    for x1, x2, y1, y2 in zip(x[[idy]][:-1], x[[idy]][1:], y[[idy]][:-1], y[[idy]][1:]):
        if x1 != x2 and y1 != y2:
            b = b + np.log(np.abs((x2 - x1) / (y2 - y1)))

    return (a - b)/len(x)

def integral_approx_estimator ( x , y ) : a , b = ( 0. , 0. ) x = np . array ( x ) y = np . array ( y ) idx , idy = ( np . argsort ( x ) , np . argsort ( y ) ) for x1 , x2 , y1 , y2 in zip ( x [ [ idx ] ] [ : - 1 ] , x [ [ idx ] ] [ 1 : ] , y [ [ idx ] ] [ : - 1 ] , y [ [ idx ] ] [ 1 : ] ) : if x1 != x2 and y1 != y2 : a = a + np . log ( np . abs ( ( y2 - y1 ) / ( x2 - x1 ) ) ) for x1 , x2 , y1 , y2 in zip ( x [ [ idy ] ] [ : - 1 ] , x [ [ idy ] ] [ 1 : ] , y [ [ idy ] ] [ : - 1 ] , y [ [ idy ] ] [ 1 : ] ) : if x1 != x2 and y1 != y2 : b = b + np . log ( np . abs ( ( x2 - x1 ) / ( y2 - y1 ) ) ) return ( a - b ) / len ( x )

Integral approximation estimator for causal inference .


def predict_proba(self, a, b, **kwargs):
        """Evaluate a pair using the IGCI model.

        :param a: Input variable 1D
        :param b: Input variable 1D
        :param kwargs: {refMeasure: Scaling method (gaussian, integral or None),
                        estimator: method used to evaluate the pairs (entropy or integral)}
        :return: Return value of the IGCI model >0 if a->b otherwise if return <0
        """
        estimators = {'entropy': lambda x, y: eval_entropy(y) - eval_entropy(x), 'integral': integral_approx_estimator}
        ref_measures = {'gaussian': lambda x: standard_scale.fit_transform(x.reshape((-1, 1))),
                        'uniform': lambda x: min_max_scale.fit_transform(x.reshape((-1, 1))), 'None': lambda x: x}

        ref_measure = ref_measures[kwargs.get('refMeasure', 'gaussian')]
        estimator = estimators[kwargs.get('estimator', 'entropy')]

        a = ref_measure(a)
        b = ref_measure(b)

        return estimator(a, b)

def predict_proba ( self , a , b , * * kwargs ) : estimators = { 'entropy' : lambda x , y : eval_entropy ( y ) - eval_entropy ( x ) , 'integral' : integral_approx_estimator } ref_measures = { 'gaussian' : lambda x : standard_scale . fit_transform ( x . reshape ( ( - 1 , 1 ) ) ) , 'uniform' : lambda x : min_max_scale . fit_transform ( x . reshape ( ( - 1 , 1 ) ) ) , 'None' : lambda x : x } ref_measure = ref_measures [ kwargs . get ( 'refMeasure' , 'gaussian' ) ] estimator = estimators [ kwargs . get ( 'estimator' , 'entropy' ) ] a = ref_measure ( a ) b = ref_measure ( b ) return estimator ( a , b )


def featurize_row(self, x, y):
        """ Projects the causal pair to the RKHS using the sampled kernel approximation.

        Args:
            x (np.ndarray): Variable 1
            y (np.ndarray): Variable 2

        Returns:
            np.ndarray: projected empirical distributions into a single fixed-size vector.
        """
        x = x.ravel()
        y = y.ravel()
        b = np.ones(x.shape)
        dx = np.cos(np.dot(self.W2, np.vstack((x, b)))).mean(1)
        dy = np.cos(np.dot(self.W2, np.vstack((y, b)))).mean(1)
        if(sum(dx) > sum(dy)):
            return np.hstack((dx, dy,
                              np.cos(np.dot(self.W, np.vstack((x, y, b)))).mean(1)))
        else:
            return np.hstack((dx, dy,
                              np.cos(np.dot(self.W, np.vstack((y, x, b)))).mean(1)))

def featurize_row ( self , x , y ) : x = x . ravel ( ) y = y . ravel ( ) b = np . ones ( x . shape ) dx = np . cos ( np . dot ( self . W2 , np . vstack ( ( x , b ) ) ) ) . mean ( 1 ) dy = np . cos ( np . dot ( self . W2 , np . vstack ( ( y , b ) ) ) ) . mean ( 1 ) if ( sum ( dx ) > sum ( dy ) ) : return np . hstack ( ( dx , dy , np . cos ( np . dot ( self . W , np . vstack ( ( x , y , b ) ) ) ) . mean ( 1 ) ) ) else : return np . hstack ( ( dx , dy , np . cos ( np . dot ( self . W , np . vstack ( ( y , x , b ) ) ) ) . mean ( 1 ) ) )

Projects the causal pair to the RKHS using the sampled kernel approximation .


def fit(self, x, y):
        """Train the model.

        Args:
            x_tr (pd.DataFrame): CEPC format dataframe containing the pairs
            y_tr (pd.DataFrame or np.ndarray): labels associated to the pairs
        """
        train = np.vstack((np.array([self.featurize_row(row.iloc[0],
                                                        row.iloc[1]) for idx, row in x.iterrows()]),
                           np.array([self.featurize_row(row.iloc[1],
                                                        row.iloc[0]) for idx, row in x.iterrows()])))
        labels = np.vstack((y, -y)).ravel()
        verbose = 1 if self.verbose else 0
        self.clf = CLF(verbose=verbose,
                       min_samples_leaf=self.L,
                       n_estimators=self.E,
                       max_depth=self.max_depth,
                       n_jobs=self.n_jobs).fit(train, labels)

def fit ( self , x , y ) : train = np . vstack ( ( np . array ( [ self . featurize_row ( row . iloc [ 0 ] , row . iloc [ 1 ] ) for idx , row in x . iterrows ( ) ] ) , np . array ( [ self . featurize_row ( row . iloc [ 1 ] , row . iloc [ 0 ] ) for idx , row in x . iterrows ( ) ] ) ) ) labels = np . vstack ( ( y , - y ) ) . ravel ( ) verbose = 1 if self . verbose else 0 self . clf = CLF ( verbose = verbose , min_samples_leaf = self . L , n_estimators = self . E , max_depth = self . max_depth , n_jobs = self . n_jobs ) . fit ( train , labels )


def predict_proba(self, x, y=None, **kwargs):
        """ Predict the causal score using a trained RCC model

        Args:
            x (numpy.array or pandas.DataFrame or pandas.Series): First variable or dataset.
            args (numpy.array): second variable (optional depending on the 1st argument).

        Returns:
            float: Causation score (Value : 1 if a->b and -1 if b->a)
        """
        if self.clf is None:
            raise ValueError("Model has to be trained before making predictions.")
        if x is pandas.Series:
            input_ = self.featurize_row(x.iloc[0], x.iloc[1]).reshape((1, -1))
        elif x is pandas.DataFrame:
            input_ = np.array([self.featurize_row(x.iloc[0], x.iloc[1]) for row in x])
        elif y is not None:
            input_ = self.featurize_row(x, y).reshape((1, -1))
        else:
            raise TypeError("DataType not understood.")
        return self.clf.predict(input_)


def predict_features(self, df_features, df_target, nh=20, idx=0, dropout=0.,
                         activation_function=th.nn.ReLU, lr=0.01, l1=0.1,  batch_size=-1,
                         train_epochs=1000, test_epochs=1000, device=None,
                         verbose=None, nb_runs=3):
        """For one variable, predict its neighbours.

        Args:
            df_features (pandas.DataFrame):
            df_target (pandas.Series):
            nh (int): number of hidden units
            idx (int): (optional) for printing purposes
            dropout (float): probability of dropout (between 0 and 1)
            activation_function (torch.nn.Module): activation function of the NN
            lr (float): learning rate of Adam
            l1 (float): L1 penalization coefficient
            batch_size (int): batch size, defaults to full-batch
            train_epochs (int): number of train epochs
            test_epochs (int): number of test epochs
            device (str): cuda or cpu device (defaults to ``cdt.SETTINGS.default_device``)
            verbose (bool): verbosity (defaults to ``cdt.SETTINGS.verbose``)
            nb_runs (int): number of bootstrap runs

        Returns:
            list: scores of each feature relatively to the target

        """
        device, verbose = SETTINGS.get_default(('device', device), ('verbose', verbose))
        x = th.FloatTensor(scale(df_features.values)).to(device)
        y = th.FloatTensor(scale(df_target.values)).to(device)
        out = []
        for i in range(nb_runs):
            model = FSGNN_model([x.size()[1] + 1, nh, 1],
                                dropout=dropout,
                                activation_function=activation_function).to(device)

            out.append(model.train(x, y, lr=0.01, l1=0.1, batch_size=-1,
                                   train_epochs=train_epochs, test_epochs=test_epochs,
                                   device=device, verbose=verbose))
        return list(np.mean(np.array(out), axis=0))

def predict_features ( self , df_features , df_target , nh = 20 , idx = 0 , dropout = 0. , activation_function = th . nn . ReLU , lr = 0.01 , l1 = 0.1 , batch_size = - 1 , train_epochs = 1000 , test_epochs = 1000 , device = None , verbose = None , nb_runs = 3 ) : device , verbose = SETTINGS . get_default ( ( 'device' , device ) , ( 'verbose' , verbose ) ) x = th . FloatTensor ( scale ( df_features . values ) ) . to ( device ) y = th . FloatTensor ( scale ( df_target . values ) ) . to ( device ) out = [ ] for i in range ( nb_runs ) : model = FSGNN_model ( [ x . size ( ) [ 1 ] + 1 , nh , 1 ] , dropout = dropout , activation_function = activation_function ) . to ( device ) out . append ( model . train ( x , y , lr = 0.01 , l1 = 0.1 , batch_size = - 1 , train_epochs = train_epochs , test_epochs = test_epochs , device = device , verbose = verbose ) ) return list ( np . mean ( np . array ( out ) , axis = 0 ) )

For one variable predict its neighbours .


def predict_undirected_graph(self, data):
        """Build a skeleton using a pairwise independence criterion.

        Args:
            data (pandas.DataFrame): Raw data table

        Returns:
            networkx.Graph: Undirected graph representing the skeleton.
        """
        graph = Graph()

        for idx_i, i in enumerate(data.columns):
            for idx_j, j in enumerate(data.columns[idx_i+1:]):
                score = self.predict(data[i].values, data[j].values)
                if abs(score) > 0.001:
                    graph.add_edge(i, j, weight=score)

        return graph

def predict_undirected_graph ( self , data ) : graph = Graph ( ) for idx_i , i in enumerate ( data . columns ) : for idx_j , j in enumerate ( data . columns [ idx_i + 1 : ] ) : score = self . predict ( data [ i ] . values , data [ j ] . values ) if abs ( score ) > 0.001 : graph . add_edge ( i , j , weight = score ) return graph

Build a skeleton using a pairwise independence criterion .


def predict(self, df_data, threshold=0.05, **kwargs):
        """Predict the skeleton of the graph from raw data.

        Returns iteratively the feature selection algorithm on each node.

        Args:
            df_data (pandas.DataFrame): data to construct a graph from
            threshold (float): cutoff value for feature selection scores
            kwargs (dict): additional arguments for algorithms

        Returns:
            networkx.Graph: predicted skeleton of the graph.
        """
        nb_jobs = kwargs.get("nb_jobs", SETTINGS.NB_JOBS)
        list_nodes = list(df_data.columns.values)
        if nb_jobs != 1:
            result_feature_selection = Parallel(n_jobs=nb_jobs)(delayed(self.run_feature_selection)
                                                                (df_data, node, idx, **kwargs)
                                                                for idx, node in enumerate(list_nodes))
        else:
            result_feature_selection = [self.run_feature_selection(df_data, node, idx, **kwargs) for idx, node in enumerate(list_nodes)]
        for idx, i in enumerate(result_feature_selection):
            try:
                i.insert(idx, 0)
            except AttributeError:  # if results are numpy arrays
                result_feature_selection[idx] = np.insert(i, idx, 0)
        matrix_results = np.array(result_feature_selection)
        matrix_results *= matrix_results.transpose()
        np.fill_diagonal(matrix_results, 0)
        matrix_results /= 2

        graph = nx.Graph()

        for (i, j), x in np.ndenumerate(matrix_results):
            if matrix_results[i, j] > threshold:
                graph.add_edge(list_nodes[i], list_nodes[j],
                               weight=matrix_results[i, j])
        for node in list_nodes:
            if node not in graph.nodes():
                graph.add_node(node)
        return graph

def
predict
(
self
,
df_data
,
threshold
=
0.05
,
*
*
kwargs
)
:
nb_jobs
=
kwargs
.
get
(
"nb_jobs"
,
SETTINGS
.
NB_JOBS
)
list_nodes
=
list
(
df_data
.
columns
.
values
)
if
nb_jobs
!=
1
:
result_feature_selection
=
Parallel
(
n_jobs
=
nb_jobs
)
(
delayed
(
self
.
run_feature_selection
)
(
df_data
,
node
,
idx
,
*
*
kwargs
)
for
idx
,
node
in
enumerate
(
list_nodes
)
)
else
:
result_feature_selection
=
[
self
.
run_feature_selection
(
df_data
,
node
,
idx
,
*
*
kwargs
)
for
idx
,
node
in
enumerate
(
list_nodes
)
]
for
idx
,
i
in
enumerate
(
result_feature_selection
)
:
try
:
i
.
insert
(
idx
,
0
)
except
AttributeError
:
# if results are numpy arrays
result_feature_selection
[
idx
]
=
np
.
insert
(
i
,
idx
,
0
)
matrix_results
=
np
.
array
(
result_feature_selection
)
matrix_results
*=
matrix_results
.
transpose
(
)
np
.
fill_diagonal
(
matrix_results
,
0
)
matrix_results
/=
2
graph
=
nx
.
Graph
(
)
for
(
i
,
j
)
,
x
in
np
.
ndenumerate
(
matrix_results
)
:
if
matrix_results
[
i
,
j
]
>
threshold
:
graph
.
add_edge
(
list_nodes
[
i
]
,
list_nodes
[
j
]
,
weight
=
matrix_results
[
i
,
j
]
)
for
node
in
list_nodes
:
if
node
not
in
graph
.
nodes
(
)
:
graph
.
add_node
(
node
)
return
graph

Predict the skeleton of the graph from raw data .


def orient_undirected_graph(self, data, graph):
        """Run GIES on an undirected graph.

        Args:
            data (pandas.DataFrame): DataFrame containing the data
            graph (networkx.Graph): Skeleton of the graph to orient

        Returns:
            networkx.DiGraph: Solution given by the GIES algorithm.

        """
        # Building setup w/ arguments.
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()
        self.arguments['{SCORE}'] = self.scores[self.score]

        fe = DataFrame(nx.adj_matrix(graph, weight=None).todense())
        fg = DataFrame(1 - fe.values)

        results = self._run_gies(data, fixedGaps=fg, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
orient_undirected_graph
(
self
,
data
,
graph
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
self
.
arguments
[
'{SCORE}'
]
=
self
.
scores
[
self
.
score
]
fe
=
DataFrame
(
nx
.
adj_matrix
(
graph
,
weight
=
)
.
todense
(
)
)
fg
=
DataFrame
(
1
fe
.
values
)
results
=
self
.
_run_gies
(
data
,
fixedGaps
=
fg
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)


def create_graph_from_data(self, data):
        """Run the GIES algorithm.

        Args:
            data (pandas.DataFrame): DataFrame containing the data

        Returns:
            networkx.DiGraph: Solution given by the GIES algorithm.
        """
        # Building setup w/ arguments.
        self.arguments['{SCORE}'] = self.scores[self.score]
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()

        results = self._run_gies(data, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
create_graph_from_data
(
self
,
data
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{SCORE}'
]
=
self
.
scores
[
self
.
score
]
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
results
=
self
.
_run_gies
(
data
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)


def _run_gies(self, data, fixedGaps=None, verbose=True):
        """Setting up and running GIES with all arguments."""
        # Run gies
        id = str(uuid.uuid4())
        os.makedirs('/tmp/cdt_gies' + id + '/')
        self.arguments['{FOLDER}'] = '/tmp/cdt_gies' + id + '/'

        def retrieve_result():
            return read_csv('/tmp/cdt_gies' + id + '/result.csv', delimiter=',').values

        try:
            data.to_csv('/tmp/cdt_gies' + id + '/data.csv', header=False, index=False)
            if fixedGaps is not None:
                fixedGaps.to_csv('/tmp/cdt_gies' + id + '/fixedgaps.csv', index=False, header=False)
                self.arguments['{SKELETON}'] = 'TRUE'
            else:
                self.arguments['{SKELETON}'] = 'FALSE'

            gies_result = launch_R_script("{}/R_templates/gies.R".format(os.path.dirname(os.path.realpath(__file__))),
                                          self.arguments, output_function=retrieve_result, verbose=verbose)
        # Cleanup
        except Exception as e:
            rmtree('/tmp/cdt_gies' + id + '')
            raise e
        except KeyboardInterrupt:
            rmtree('/tmp/cdt_gies' + id + '/')
            raise KeyboardInterrupt
        rmtree('/tmp/cdt_gies' + id + '')
        return gies_result

def
_run_gies
(
self
,
data
,
fixedGaps
=
,
verbose
=
True
)
:
# Run gies
id
=
str
(
uuid
.
uuid4
(
)
)
os
.
makedirs
(
'/tmp/cdt_gies'
+
id
+
'/'
)
self
.
arguments
[
'{FOLDER}'
]
=
'/tmp/cdt_gies'
+
id
+
'/'
def
retrieve_result
(
)
:
return
read_csv
(
'/tmp/cdt_gies'
+
id
+
'/result.csv'
,
delimiter
=
','
)
.
values
try
:
data
.
to_csv
(
'/tmp/cdt_gies'
+
id
+
'/data.csv'
,
header
=
False
,
index
=
False
)
if
fixedGaps
is
not
:
fixedGaps
.
to_csv
(
'/tmp/cdt_gies'
+
id
+
'/fixedgaps.csv'
,
index
=
False
,
header
=
False
)
self
.
arguments
[
'{SKELETON}'
]
=
'TRUE'
else
:
self
.
arguments
[
'{SKELETON}'
]
=
'FALSE'
gies_result
=
launch_R_script
(
"{}/R_templates/gies.R"
.
format
(
os
.
path
.
dirname
(
os
.
path
.
realpath
(
__file__
)
)
)
,
self
.
arguments
,
output_function
=
retrieve_result
,
verbose
=
verbose
)
# Cleanup
except
Exception
as
e
:
rmtree
(
'/tmp/cdt_gies'
+
id
+
''
)
raise
e
except
KeyboardInterrupt
:
rmtree
(
'/tmp/cdt_gies'
+
id
+
'/'
)
raise
KeyboardInterrupt
rmtree
(
'/tmp/cdt_gies'
+
id
+
''
)
return
gies_result

Setting up and running GIES with all arguments .


def plot_curves(i_batch, adv_loss, gen_loss, l1_reg, cols):
    """Plot SAM's various losses."""
    from matplotlib import pyplot as plt
    if i_batch == 0:
        try:
            ax.clear()
            ax.plot(range(len(adv_plt)), adv_plt, "r-",
                    linewidth=1.5, markersize=4,
                    label="Discriminator")
            ax.plot(range(len(adv_plt)), gen_plt, "g-", linewidth=1.5,
                    markersize=4, label="Generators")
            ax.plot(range(len(adv_plt)), l1_plt, "b-",
                    linewidth=1.5, markersize=4,
                    label="L1-Regularization")
            plt.legend()

            adv_plt.append(adv_loss.cpu().data[0])
            gen_plt.append(gen_loss.cpu().data[0] / cols)
            l1_plt.append(l1_reg.cpu().data[0])

            plt.pause(0.0001)

        except NameError:
            plt.ion()
            fig, ax = plt.figure()
            plt.xlabel("Epoch")
            plt.ylabel("Losses")

            plt.pause(0.0001)

            adv_plt = [adv_loss.cpu().data[0]]
            gen_plt = [gen_loss.cpu().data[0] / cols]
            l1_plt = [l1_reg.cpu().data[0]]

    else:
        adv_plt.append(adv_loss.cpu().data[0])
        gen_plt.append(gen_loss.cpu().data[0] / cols)
        l1_plt.append(l1_reg.cpu().data[0])

def plot_curves ( i_batch , adv_loss , gen_loss , l1_reg , cols ) : from matplotlib import pyplot as plt if i_batch == 0 : try : ax . clear ( ) ax . plot ( range ( len ( adv_plt ) ) , adv_plt , "r-" , linewidth = 1.5 , markersize = 4 , label = "Discriminator" ) ax . plot ( range ( len ( adv_plt ) ) , gen_plt , "g-" , linewidth = 1.5 , markersize = 4 , label = "Generators" ) ax . plot ( range ( len ( adv_plt ) ) , l1_plt , "b-" , linewidth = 1.5 , markersize = 4 , label = "L1-Regularization" ) plt . legend ( ) adv_plt . append ( adv_loss . cpu ( ) . data [ 0 ] ) gen_plt . append ( gen_loss . cpu ( ) . data [ 0 ] / cols ) l1_plt . append ( l1_reg . cpu ( ) . data [ 0 ] ) plt . pause ( 0.0001 ) except NameError : plt . ion ( ) fig , ax = plt . figure ( ) plt . xlabel ( "Epoch" ) plt . ylabel ( "Losses" ) plt . pause ( 0.0001 ) adv_plt = [ adv_loss . cpu ( ) . data [ 0 ] ] gen_plt = [ gen_loss . cpu ( ) . data [ 0 ] / cols ] l1_plt = [ l1_reg . cpu ( ) . data [ 0 ] ] else : adv_plt . append ( adv_loss . cpu ( ) . data [ 0 ] ) gen_plt . append ( gen_loss . cpu ( ) . data [ 0 ] / cols ) l1_plt . append ( l1_reg . cpu ( ) . data [ 0 ] )


def plot_gen(epoch, batch, generated_variables, pairs_to_plot=[[0, 1]]):
    """Plot generated pairs of variables."""
    from matplotlib import pyplot as plt
    if epoch == 0:
        plt.ion()
    plt.clf()
    for (i, j) in pairs_to_plot:

        plt.scatter(generated_variables[i].data.cpu().numpy(
        ), batch.data.cpu().numpy()[:, j], label="Y -> X")
        plt.scatter(batch.data.cpu().numpy()[
            :, i], generated_variables[j].data.cpu().numpy(), label="X -> Y")

        plt.scatter(batch.data.cpu().numpy()[:, i], batch.data.cpu().numpy()[
            :, j], label="original data")
        plt.legend()

    plt.pause(0.01)

def
plot_gen
(
epoch
,
batch
,
generated_variables
,
pairs_to_plot
=
[
[
0
,
1
]
]
)
:
from
matplotlib
import
pyplot
as
plt
if
epoch
==
0
:
plt
.
ion
(
)
plt
.
clf
(
)
for
(
i
,
j
)
in
pairs_to_plot
:
plt
.
scatter
(
generated_variables
[
i
]
.
data
.
cpu
(
)
.
numpy
(
)
,
batch
.
data
.
cpu
(
)
.
numpy
(
)
[
:
,
j
]
,
label
=
"Y -> X"
)
plt
.
scatter
(
batch
.
data
.
cpu
(
)
.
numpy
(
)
[
:
,
i
]
,
generated_variables
[
j
]
.
data
.
cpu
(
)
.
numpy
(
)
,
label
=
"X -> Y"
)
plt
.
scatter
(
batch
.
data
.
cpu
(
)
.
numpy
(
)
[
:
,
i
]
,
batch
.
data
.
cpu
(
)
.
numpy
(
)
[
:
,
j
]
,
label
=
"original data"
)
plt
.
legend
(
)
plt
.
pause
(
0.01
)


def reset_parameters(self):
        """Reset the parameters."""
        stdv = 1. / math.sqrt(self.weight.size(1))
        self.weight.data.uniform_(-stdv, stdv)
        if self.bias is not None:
            self.bias.data.uniform_(-stdv, stdv)

def reset_parameters ( self ) : stdv = 1. / math . sqrt ( self . weight . size ( 1 ) ) self . weight . data . uniform_ ( - stdv , stdv ) if self . bias is not None : self . bias . data . uniform_ ( - stdv , stdv )


def forward(self, input):
        """Feed-forward through the network."""
        return th.nn.functional.linear(input, self.weight.div(self.weight.pow(2).sum(0).sqrt()))

def forward ( self , input ) : return th . nn . functional . linear ( input , self . weight . div ( self . weight . pow ( 2 ) . sum ( 0 ) . sqrt ( ) ) )


def predict(self, data, graph=None, nruns=6, njobs=None, gpus=0, verbose=None,
                plot=False, plot_generated_pair=False, return_list_results=False):
        """Execute SAM on a dataset given a skeleton or not.

        Args:
            data (pandas.DataFrame): Observational data for estimation of causal relationships by SAM
            skeleton (numpy.ndarray): A priori knowledge about the causal relationships as an adjacency matrix.
                      Can be fed either directed or undirected links.
            nruns (int): Number of runs to be made for causal estimation.
                   Recommended: >=12 for optimal performance.
            njobs (int): Numbers of jobs to be run in Parallel.
                   Recommended: 1 if no GPU available, 2*number of GPUs else.
            gpus (int): Number of available GPUs for the algorithm.
            verbose (bool): verbose mode
            plot (bool): Plot losses interactively. Not recommended if nruns>1
            plot_generated_pair (bool): plots a generated pair interactively.  Not recommended if nruns>1
        Returns:
            networkx.DiGraph: Graph estimated by SAM, where A[i,j] is the term
            of the ith variable for the jth generator.
        """
        verbose, njobs = SETTINGS.get_default(('verbose', verbose), ('nb_jobs', njobs))
        if njobs != 1:
            list_out = Parallel(n_jobs=njobs)(delayed(run_SAM)(data,
                                                               skeleton=graph,
                                                               lr_gen=self.lr, lr_disc=self.dlr,
                                                               regul_param=self.l1, nh=self.nh, dnh=self.dnh,
                                                               gpu=bool(gpus), train_epochs=self.train,
                                                               test_epochs=self.test, batch_size=self.batchsize,
                                                               plot=plot, verbose=verbose, gpu_no=idx % max(gpus, 1))
                                              for idx in range(nruns))
        else:
            list_out = [run_SAM(data, skeleton=graph,
                                lr_gen=self.lr, lr_disc=self.dlr,
                                regul_param=self.l1, nh=self.nh, dnh=self.dnh,
                                gpu=bool(gpus), train_epochs=self.train,
                                test_epochs=self.test, batch_size=self.batchsize,
                                plot=plot, verbose=verbose, gpu_no=0)
                        for idx in range(nruns)]
        if return_list_results:
            return list_out
        else:
            W = list_out[0]
            for w in list_out[1:]:
                W += w
            W /= nruns
        return nx.relabel_nodes(nx.DiGraph(W), {idx: i for idx, i in enumerate(data.columns)})

def predict ( self , data , graph = None , nruns = 6 , njobs = None , gpus = 0 , verbose = None , plot = False , plot_generated_pair = False , return_list_results = False ) : verbose , njobs = SETTINGS . get_default ( ( 'verbose' , verbose ) , ( 'nb_jobs' , njobs ) ) if njobs != 1 : list_out = Parallel ( n_jobs = njobs ) ( delayed ( run_SAM ) ( data , skeleton = graph , lr_gen = self . lr , lr_disc = self . dlr , regul_param = self . l1 , nh = self . nh , dnh = self . dnh , gpu = bool ( gpus ) , train_epochs = self . train , test_epochs = self . test , batch_size = self . batchsize , plot = plot , verbose = verbose , gpu_no = idx % max ( gpus , 1 ) ) for idx in range ( nruns ) ) else : list_out = [ run_SAM ( data , skeleton = graph , lr_gen = self . lr , lr_disc = self . dlr , regul_param = self . l1 , nh = self . nh , dnh = self . dnh , gpu = bool ( gpus ) , train_epochs = self . train , test_epochs = self . test , batch_size = self . batchsize , plot = plot , verbose = verbose , gpu_no = 0 ) for idx in range ( nruns ) ] if return_list_results : return list_out else : W = list_out [ 0 ] for w in list_out [ 1 : ] : W += w W /= nruns return nx . relabel_nodes ( nx . DiGraph ( W ) , { idx : i for idx , i in enumerate ( data . columns ) } )

Execute SAM on a dataset given a skeleton or not .


def predict_proba(self, a, b, **kwargs):
        """ Infer causal relationships between 2 variables using the RECI statistic

        :param a: Input variable 1
        :param b: Input variable 2
        :return: Causation coefficient (Value : 1 if a->b and -1 if b->a)
        :rtype: float
        """
        return self.b_fit_score(b, a) - self.b_fit_score(a, b)

def predict_proba ( self , a , b , * * kwargs ) : return self . b_fit_score ( b , a ) - self . b_fit_score ( a , b )


def b_fit_score(self, x, y):
        """ Compute the RECI fit score

        Args:
            x (numpy.ndarray): Variable 1
            y (numpy.ndarray): Variable 2

        Returns:
            float: RECI fit score

        """
        x = np.reshape(minmax_scale(x), (-1, 1))
        y = np.reshape(minmax_scale(y), (-1, 1))
        poly = PolynomialFeatures(degree=self.degree)
        poly_x = poly.fit_transform(x)

        poly_x[:,1] = 0
        poly_x[:,2] = 0

        regressor = LinearRegression()
        regressor.fit(poly_x, y)

        y_predict = regressor.predict(poly_x)
        error = mean_squared_error(y_predict, y)

        return error

def b_fit_score ( self , x , y ) : x = np . reshape ( minmax_scale ( x ) , ( - 1 , 1 ) ) y = np . reshape ( minmax_scale ( y ) , ( - 1 , 1 ) ) poly = PolynomialFeatures ( degree = self . degree ) poly_x = poly . fit_transform ( x ) poly_x [ : , 1 ] = 0 poly_x [ : , 2 ] = 0 regressor = LinearRegression ( ) regressor . fit ( poly_x , y ) y_predict = regressor . predict ( poly_x ) error = mean_squared_error ( y_predict , y ) return error


def predict_proba(self, a, b, **kwargs):
        """ Infer causal relationships between 2 variables using the CDS statistic

        Args:
            a (numpy.ndarray): Variable 1
            b (numpy.ndarray): Variable 2

        Returns:
            float: Causation score (Value : 1 if a->b and -1 if b->a)
        """
        return self.cds_score(b, a) - self.cds_score(a, b)

def predict_proba ( self , a , b , * * kwargs ) : return self . cds_score ( b , a ) - self . cds_score ( a , b )


def predict_proba(self, a, b, **kwargs):
        """Prediction method for pairwise causal inference using the ANM model.

        Args:
            a (numpy.ndarray): Variable 1
            b (numpy.ndarray): Variable 2

        Returns:
            float: Causation score (Value : 1 if a->b and -1 if b->a)
        """
        a = scale(a).reshape((-1, 1))
        b = scale(b).reshape((-1, 1))

        return self.anm_score(b, a) - self.anm_score(a, b)

def predict_proba ( self , a , b , * * kwargs ) : a = scale ( a ) . reshape ( ( - 1 , 1 ) ) b = scale ( b ) . reshape ( ( - 1 , 1 ) ) return self . anm_score ( b , a ) - self . anm_score ( a , b )

Prediction method for pairwise causal inference using the ANM model .


def anm_score(self, x, y):
        """Compute the fitness score of the ANM model in the x->y direction.

        Args:
            a (numpy.ndarray): Variable seen as cause
            b (numpy.ndarray): Variable seen as effect

        Returns:
            float: ANM fit score
        """
        gp = GaussianProcessRegressor().fit(x, y)
        y_predict = gp.predict(x)
        indepscore = normalized_hsic(y_predict - y, x)

        return indepscore

def anm_score ( self , x , y ) : gp = GaussianProcessRegressor ( ) . fit ( x , y ) y_predict = gp . predict ( x ) indepscore = normalized_hsic ( y_predict - y , x ) return indepscore

Compute the fitness score of the ANM model in the x - > y direction .


def orient_undirected_graph(self, data, graph, **kwargs):
        """Run PC on an undirected graph.

        Args:
            data (pandas.DataFrame): DataFrame containing the data
            graph (networkx.Graph): Skeleton of the graph to orient

        Returns:
            networkx.DiGraph: Solution given by PC on the given skeleton.
        """
        # Building setup w/ arguments.
        self.arguments['{CITEST}'] = self.dir_CI_test[self.CI_test]
        self.arguments['{METHOD_INDEP}'] = self.dir_method_indep[self.method_indep]
        self.arguments['{DIRECTED}'] = 'TRUE'
        self.arguments['{ALPHA}'] = str(self.alpha)
        self.arguments['{NJOBS}'] = str(self.nb_jobs)
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()

        fe = DataFrame(nx.adj_matrix(graph, weight=None).todense())
        fg = DataFrame(1 - fe.values)

        results = self._run_pc(data, fixedEdges=fe, fixedGaps=fg, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
orient_undirected_graph
(
self
,
data
,
graph
,
*
*
kwargs
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{CITEST}'
]
=
self
.
dir_CI_test
[
self
.
CI_test
]
self
.
arguments
[
'{METHOD_INDEP}'
]
=
self
.
dir_method_indep
[
self
.
method_indep
]
self
.
arguments
[
'{DIRECTED}'
]
=
'TRUE'
self
.
arguments
[
'{ALPHA}'
]
=
str
(
self
.
alpha
)
self
.
arguments
[
'{NJOBS}'
]
=
str
(
self
.
nb_jobs
)
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
fe
=
DataFrame
(
nx
.
adj_matrix
(
graph
,
weight
=
)
.
todense
(
)
)
fg
=
DataFrame
(
1
fe
.
values
)
results
=
self
.
_run_pc
(
data
,
fixedEdges
=
fe
,
fixedGaps
=
fg
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)


def create_graph_from_data(self, data, **kwargs):
        """Run the PC algorithm.

        Args:
            data (pandas.DataFrame): DataFrame containing the data

        Returns:
            networkx.DiGraph: Solution given by PC on the given data.
       """
        # Building setup w/ arguments.
        self.arguments['{CITEST}'] = self.dir_CI_test[self.CI_test]
        self.arguments['{METHOD_INDEP}'] = self.dir_method_indep[self.method_indep]
        self.arguments['{DIRECTED}'] = 'TRUE'
        self.arguments['{ALPHA}'] = str(self.alpha)
        self.arguments['{NJOBS}'] = str(self.nb_jobs)
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()

        results = self._run_pc(data, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
create_graph_from_data
(
self
,
data
,
*
*
kwargs
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{CITEST}'
]
=
self
.
dir_CI_test
[
self
.
CI_test
]
self
.
arguments
[
'{METHOD_INDEP}'
]
=
self
.
dir_method_indep
[
self
.
method_indep
]
self
.
arguments
[
'{DIRECTED}'
]
=
'TRUE'
self
.
arguments
[
'{ALPHA}'
]
=
str
(
self
.
alpha
)
self
.
arguments
[
'{NJOBS}'
]
=
str
(
self
.
nb_jobs
)
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
results
=
self
.
_run_pc
(
data
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)


def _run_pc(self, data, fixedEdges=None, fixedGaps=None, verbose=True):
        """Setting up and running pc with all arguments."""
        # Checking coherence of arguments
        # print(self.arguments)
        if (self.arguments['{CITEST}'] == self.dir_CI_test['hsic']
           and self.arguments['{METHOD_INDEP}'] == self.dir_method_indep['corr']):
            warnings.warn('Selected method for indep is unfit for the hsic test,'
                          ' setting the hsic.gamma method.')
            self.arguments['{METHOD_INDEP}'] = self.dir_method_indep['hsic_gamma']

        elif (self.arguments['{CITEST}'] == self.dir_CI_test['gaussian']
              and self.arguments['{METHOD_INDEP}'] != self.dir_method_indep['corr']):
            warnings.warn('Selected method for indep is unfit for the selected test,'
                          ' setting the classic correlation-based method.')
            self.arguments['{METHOD_INDEP}'] = self.dir_method_indep['corr']

        # Run PC
        id = str(uuid.uuid4())
        os.makedirs('/tmp/cdt_pc' + id + '/')
        self.arguments['{FOLDER}'] = '/tmp/cdt_pc' + id + '/'

        def retrieve_result():
            return read_csv('/tmp/cdt_pc' + id + '/result.csv', delimiter=',').values

        try:
            data.to_csv('/tmp/cdt_pc' + id + '/data.csv', header=False, index=False)
            if fixedGaps is not None and fixedEdges is not None:
                fixedGaps.to_csv('/tmp/cdt_pc' + id + '/fixedgaps.csv', index=False, header=False)
                fixedEdges.to_csv('/tmp/cdt_pc' + id + '/fixededges.csv', index=False, header=False)
                self.arguments['{SKELETON}'] = 'TRUE'
            else:
                self.arguments['{SKELETON}'] = 'FALSE'

            pc_result = launch_R_script("{}/R_templates/pc.R".format(os.path.dirname(os.path.realpath(__file__))),
                                        self.arguments, output_function=retrieve_result, verbose=verbose)
        # Cleanup
        except Exception as e:
            rmtree('/tmp/cdt_pc' + id + '')
            raise e
        except KeyboardInterrupt:
            rmtree('/tmp/cdt_pc' + id + '/')
            raise KeyboardInterrupt
        rmtree('/tmp/cdt_pc' + id + '')
        return pc_result

Setting up and running pc with all arguments .


def predict(self, data, alpha=0.01, max_iter=2000, **kwargs):
        """ Predict the graph skeleton.

        Args:
            data (pandas.DataFrame): observational data
            alpha (float): regularization parameter
            max_iter (int): maximum number of iterations

        Returns:
            networkx.Graph: Graph skeleton
        """
        edge_model = GraphLasso(alpha=alpha, max_iter=max_iter)
        edge_model.fit(data.values)

        return nx.relabel_nodes(nx.DiGraph(edge_model.get_precision()),
                                {idx: i for idx, i in enumerate(data.columns)})

def predict ( self , data , alpha = 0.01 , max_iter = 2000 , * * kwargs ) : edge_model = GraphLasso ( alpha = alpha , max_iter = max_iter ) edge_model . fit ( data . values ) return nx . relabel_nodes ( nx . DiGraph ( edge_model . get_precision ( ) ) , { idx : i for idx , i in enumerate ( data . columns ) } )


def autoset_settings(set_var):
    """Autoset GPU parameters using CUDA_VISIBLE_DEVICES variables.

    Return default config if variable not set.
    :param set_var: Variable to set. Must be of type ConfigSettings
    """
    try:
        devices = ast.literal_eval(os.environ["CUDA_VISIBLE_DEVICES"])
        if type(devices) != list and type(devices) != tuple:
            devices = [devices]
        if len(devices) != 0:
            set_var.GPU = len(devices)
            set_var.NB_JOBS = len(devices)
            warnings.warn("Detecting CUDA devices : {}".format(devices))

    except KeyError:
        set_var.GPU = check_cuda_devices()
        set_var.NB_JOBS = set_var.GPU
        warnings.warn("Detecting {} CUDA devices.".format(set_var.GPU))
        if not set_var.GPU:
            warnings.warn("No GPU automatically detected. Setting SETTINGS.GPU to 0, " +
                          "and SETTINGS.NB_JOBS to cpu_count.")
            set_var.GPU = 0
            set_var.NB_JOBS = multiprocessing.cpu_count()

    return set_var

Autoset GPU parameters using CUDA_VISIBLE_DEVICES variables .


def check_cuda_devices():
    """Output some information on CUDA-enabled devices on your computer,
    including current memory usage. Modified to only get number of devices.

    It's a port of https://gist.github.com/f0k/0d6431e3faa60bffc788f8b4daa029b1
    from C to Python with ctypes, so it can run without compiling
    anything. Note that this is a direct translation with no attempt to
    make the code Pythonic. It's meant as a general demonstration on how
    to obtain CUDA device information from Python without resorting to
    nvidia-smi or a compiled Python extension.

    .. note:: Author: Jan Schlüter, https://gist.github.com/63a664160d016a491b2cbea15913d549.git
    """
    import ctypes

    # Some constants taken from cuda.h
    CUDA_SUCCESS = 0

    libnames = ('libcuda.so', 'libcuda.dylib', 'cuda.dll')
    for libname in libnames:
        try:
            cuda = ctypes.CDLL(libname)
        except OSError:
            continue
        else:
            break
    else:
        # raise OSError("could not load any of: " + ' '.join(libnames))
        return 0

    nGpus = ctypes.c_int()
    error_str = ctypes.c_char_p()

    result = cuda.cuInit(0)
    if result != CUDA_SUCCESS:
        cuda.cuGetErrorString(result, ctypes.byref(error_str))
        # print("cuInit failed with error code %d: %s" % (result, error_str.value.decode()))
        return 0
    result = cuda.cuDeviceGetCount(ctypes.byref(nGpus))
    if result != CUDA_SUCCESS:
        cuda.cuGetErrorString(result, ctypes.byref(error_str))
        # print("cuDeviceGetCount failed with error code %d: %s" % (result, error_str.value.decode()))
        return 0
    # print("Found %d device(s)." % nGpus.value)
    return nGpus.value

Output some information on CUDA - enabled devices on your computer including current memory usage . Modified to only get number of devices .


def get_default(self, *args, **kwargs):
        """Get the default parameters as defined in the Settings instance.

        This function proceeds to seamlessly retrieve the argument to pass
        through, depending on either it was overidden or not: If no argument
        was overridden in a function of the toolbox, the default argument will
        be set to ``None``, and this function will retrieve the default
        parameters as defined by the ``cdt.SETTINGS`` 's attributes.

        It has two modes of processing:

        1. **kwargs for retrieving a single argument: ``get_default(argument_name=value)``.
        2. *args through a list of tuples of the shape ``('argument_name', value)`` to retrieve multiple values at once.
        """
        def retrieve_param(i):
            try:
                return self.__getattribute__(i)
            except AttributeError:
                if i == "device":
                    return self.default_device
                else:
                    return self.__getattribute__(i.upper())
        if len(args) == 0:
            if len(kwargs) == 1 and kwargs[list(kwargs.keys())[0]] is not None:
                return kwargs[list(kwargs.keys())[0]]
            elif len(kwargs) == 1:
                return retrieve_param(list(kwargs.keys())[0])
            else:
                raise TypeError("As dict is unordered, it is impossible to give"
                                "the parameters in the correct order.")
        else:
            out = []
            for i in args:
                if i[1] is None:
                    out.append(retrieve_param(i[0]))
                else:
                    out.append(i[1])
            return out

Get the default parameters as defined in the Settings instance .


def read_causal_pairs(filename, scale=True, **kwargs):
    """Convert a ChaLearn Cause effect pairs challenge format into numpy.ndarray.

    :param filename: path of the file to read or DataFrame containing the data
    :type filename: str or pandas.DataFrame
    :param scale: Scale the data
    :type scale: bool
    :param kwargs: parameters to be passed to pandas.read_csv
    :return: Dataframe composed of (SampleID, a (numpy.ndarray) , b (numpy.ndarray))
    :rtype: pandas.DataFrame
    """
    def convert_row(row, scale):
        """Convert a CCEPC row into numpy.ndarrays.

        :param row:
        :type row: pandas.Series
        :return: tuple of sample ID and the converted data into numpy.ndarrays
        :rtype: tuple
        """
        a = row["A"].split(" ")
        b = row["B"].split(" ")

        if a[0] == "":
            a.pop(0)
            b.pop(0)
        if a[-1] == "":
            a.pop(-1)
            b.pop(-1)

        a = array([float(i) for i in a])
        b = array([float(i) for i in b])
        if scale:
            a = scaler(a)
            b = scaler(b)
        return row['SampleID'], a, b
    if isinstance(filename, str):
        data = read_csv(filename, **kwargs)
    elif isinstance(filename, DataFrame):
        data = filename
    else:
        raise TypeError("Type not supported.")
    conv_data = []

    for idx, row in data.iterrows():
        conv_data.append(convert_row(row, scale))
    df = DataFrame(conv_data, columns=['SampleID', 'A', 'B'])
    df = df.set_index("SampleID")
    return df

Convert a ChaLearn Cause effect pairs challenge format into numpy . ndarray .


def forward(self, pred, target):
        """Compute the loss model.

        :param pred: predicted Variable
        :param target: Target Variable
        :return: Loss
        """
        loss = th.FloatTensor([0])
        for i in range(1, self.moments):
            mk_pred = th.mean(th.pow(pred, i), 0)
            mk_tar = th.mean(th.pow(target, i), 0)

            loss.add_(th.mean((mk_pred - mk_tar) ** 2))  # L2

        return loss

def
forward
(
self
,
pred
,
target
)
:
loss
=
th
.
FloatTensor
(
[
0
]
)
for
i
in
range
(
1
,
self
.
moments
)
:
mk_pred
=
th
.
mean
(
th
.
pow
(
pred
,
i
)
,
0
)
mk_tar
=
th
.
mean
(
th
.
pow
(
target
,
i
)
,
0
)
loss
.
add_
(
th
.
mean
(
(
mk_pred
mk_tar
)
**
2
)
)
# L2
return
loss


def predict(self, x, *args, **kwargs):
        """Generic predict method, chooses which subfunction to use for a more
        suited.

        Depending on the type of `x` and of `*args`, this function process to execute
        different functions in the priority order:

        1. If ``args[0]`` is a ``networkx.(Di)Graph``, then ``self.orient_graph`` is executed.
        2. If ``args[0]`` exists, then ``self.predict_proba`` is executed.
        3. If ``x`` is a ``pandas.DataFrame``, then ``self.predict_dataset`` is executed.
        4. If ``x`` is a ``pandas.Series``, then ``self.predict_proba`` is executed.

        Args:
            x (numpy.array or pandas.DataFrame or pandas.Series): First variable or dataset.
            args (numpy.array or networkx.Graph): graph or second variable.

        Returns:
            pandas.Dataframe or networkx.Digraph: predictions output
        """
        if len(args) > 0:
            if type(args[0]) == nx.Graph or type(args[0]) == nx.DiGraph:
                return self.orient_graph(x, *args, **kwargs)
            else:
                return self.predict_proba(x, *args, **kwargs)
        elif type(x) == DataFrame:
            return self.predict_dataset(x, *args, **kwargs)
        elif type(x) == Series:
            return self.predict_proba(x.iloc[0], x.iloc[1], *args, **kwargs)

def predict ( self , x , * args , * * kwargs ) : if len ( args ) > 0 : if type ( args [ 0 ] ) == nx . Graph or type ( args [ 0 ] ) == nx . DiGraph : return self . orient_graph ( x , * args , * * kwargs ) else : return self . predict_proba ( x , * args , * * kwargs ) elif type ( x ) == DataFrame : return self . predict_dataset ( x , * args , * * kwargs ) elif type ( x ) == Series : return self . predict_proba ( x . iloc [ 0 ] , x . iloc [ 1 ] , * args , * * kwargs )

Generic predict method chooses which subfunction to use for a more suited .


def predict_dataset(self, x, **kwargs):
        """Generic dataset prediction function.

        Runs the score independently on all pairs.

        Args:
            x (pandas.DataFrame): a CEPC format Dataframe.
            kwargs (dict): additional arguments for the algorithms

        Returns:
            pandas.DataFrame: a Dataframe with the predictions.
        """
        printout = kwargs.get("printout", None)
        pred = []
        res = []
        x.columns = ["A", "B"]
        for idx, row in x.iterrows():
            a = scale(row['A'].reshape((len(row['A']), 1)))
            b = scale(row['B'].reshape((len(row['B']), 1)))

            pred.append(self.predict_proba(a, b, idx=idx))

            if printout is not None:
                res.append([row['SampleID'], pred[-1]])
                DataFrame(res, columns=['SampleID', 'Predictions']).to_csv(
                    printout, index=False)
        return pred

def predict_dataset ( self , x , * * kwargs ) : printout = kwargs . get ( "printout" , None ) pred = [ ] res = [ ] x . columns = [ "A" , "B" ] for idx , row in x . iterrows ( ) : a = scale ( row [ 'A' ] . reshape ( ( len ( row [ 'A' ] ) , 1 ) ) ) b = scale ( row [ 'B' ] . reshape ( ( len ( row [ 'B' ] ) , 1 ) ) ) pred . append ( self . predict_proba ( a , b , idx = idx ) ) if printout is not None : res . append ( [ row [ 'SampleID' ] , pred [ - 1 ] ] ) DataFrame ( res , columns = [ 'SampleID' , 'Predictions' ] ) . to_csv ( printout , index = False ) return pred


def orient_graph(self, df_data, graph, nb_runs=6, printout=None, **kwargs):
        """Orient an undirected graph using the pairwise method defined by the subclass.

        The pairwise method is ran on every undirected edge.

        Args:
            df_data (pandas.DataFrame): Data
            umg (networkx.Graph): Graph to orient
            nb_runs (int): number of times to rerun for each pair (bootstrap)
            printout (str): (optional) Path to file where to save temporary results

        Returns:
            networkx.DiGraph: a directed graph, which might contain cycles

        .. warning:
           Requirement : Name of the nodes in the graph correspond to name of
           the variables in df_data
        """
        if type(graph) == nx.DiGraph:
            edges = [a for a in list(graph.edges()) if (a[1], a[0]) in list(graph.edges())]
            oriented_edges = [a for a in list(graph.edges()) if (a[1], a[0]) not in list(graph.edges())]
            for a in edges:
                if (a[1], a[0]) in list(graph.edges()):
                    edges.remove(a)
            output = nx.DiGraph()
            for i in oriented_edges:
                output.add_edge(*i)

        elif type(graph) == nx.Graph:
            edges = list(graph.edges())
            output = nx.DiGraph()

        else:
            raise TypeError("Data type not understood.")

        res = []

        for idx, (a, b) in enumerate(edges):
            weight = self.predict_proba(
                df_data[a].values.reshape((-1, 1)), df_data[b].values.reshape((-1, 1)), idx=idx,
                nb_runs=nb_runs, **kwargs)
            if weight > 0:  # a causes b
                output.add_edge(a, b, weight=weight)
            else:
                output.add_edge(b, a, weight=abs(weight))
            if printout is not None:
                res.append([str(a) + '-' + str(b), weight])
                DataFrame(res, columns=['SampleID', 'Predictions']).to_csv(
                    printout, index=False)

        for node in list(df_data.columns.values):
            if node not in output.nodes():
                output.add_node(node)

        return output

def
orient_graph
(
self
,
df_data
,
graph
,
nb_runs
=
6
,
printout
=
,
*
*
kwargs
)
:
if
type
(
graph
)
==
nx
.
DiGraph
:
edges
=
[
a
for
a
in
list
(
graph
.
edges
(
)
)
if
(
a
[
1
]
,
a
[
0
]
)
in
list
(
graph
.
edges
(
)
)
]
oriented_edges
=
[
a
for
a
in
list
(
graph
.
edges
(
)
)
if
(
a
[
1
]
,
a
[
0
]
)
not
in
list
(
graph
.
edges
(
)
)
]
for
a
in
edges
:
if
(
a
[
1
]
,
a
[
0
]
)
in
list
(
graph
.
edges
(
)
)
:
edges
.
remove
(
a
)
output
=
nx
.
DiGraph
(
)
for
i
in
oriented_edges
:
output
.
add_edge
(
*
i
)
elif
type
(
graph
)
==
nx
.
Graph
:
edges
=
list
(
graph
.
edges
(
)
)
output
=
nx
.
DiGraph
(
)
else
:
raise
TypeError
(
"Data type not understood."
)
res
=
[
]
for
idx
,
(
a
,
b
)
in
enumerate
(
edges
)
:
weight
=
self
.
predict_proba
(
df_data
[
a
]
.
values
.
reshape
(
(
1
,
1
)
)
,
df_data
[
b
]
.
values
.
reshape
(
(
1
,
1
)
)
,
idx
=
idx
,
nb_runs
=
nb_runs
,
*
*
kwargs
)
if
weight
>
0
:
# a causes b
output
.
add_edge
(
a
,
b
,
weight
=
weight
)
else
:
output
.
add_edge
(
b
,
a
,
weight
=
abs
(
weight
)
)
if
printout
is
not
:
res
.
append
(
[
str
(
a
)
+
'-'
+
str
(
b
)
,
weight
]
)
DataFrame
(
res
,
columns
=
[
'SampleID'
,
'Predictions'
]
)
.
to_csv
(
printout
,
index
=
False
)
for
node
in
list
(
df_data
.
columns
.
values
)
:
if
node
not
in
output
.
nodes
(
)
:
output
.
add_node
(
node
)
return
output

Orient an undirected graph using the pairwise method defined by the subclass .


def orient_undirected_graph(self, data, graph):
        """Run the algorithm on an undirected graph.

        Args:
            data (pandas.DataFrame): DataFrame containing the data
            graph (networkx.Graph): Skeleton of the graph to orient

        Returns:
            networkx.DiGraph: Solution on the given skeleton.

        """
        # Building setup w/ arguments.
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()
        self.arguments['{SCORE}'] = self.score
        self.arguments['{BETA}'] = str(self.beta)
        self.arguments['{OPTIM}'] = str(self.optim).upper()
        self.arguments['{ALPHA}'] = str(self.alpha)

        whitelist = DataFrame(list(nx.edges(graph)), columns=["from", "to"])
        blacklist = DataFrame(list(nx.edges(nx.DiGraph(DataFrame(-nx.adj_matrix(graph, weight=None).to_dense() + 1,
                                                                 columns=list(graph.nodes()),
                                                                 index=list(graph.nodes()))))), columns=["from", "to"])
        results = self._run_bnlearn(data, whitelist=whitelist,
                                   blacklist=blacklist, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
orient_undirected_graph
(
self
,
data
,
graph
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
self
.
arguments
[
'{SCORE}'
]
=
self
.
score
self
.
arguments
[
'{BETA}'
]
=
str
(
self
.
beta
)
self
.
arguments
[
'{OPTIM}'
]
=
str
(
self
.
optim
)
.
upper
(
)
self
.
arguments
[
'{ALPHA}'
]
=
str
(
self
.
alpha
)
whitelist
=
DataFrame
(
list
(
nx
.
edges
(
graph
)
)
,
columns
=
[
"from"
,
"to"
]
)
blacklist
=
DataFrame
(
list
(
nx
.
edges
(
nx
.
DiGraph
(
DataFrame
(
nx
.
adj_matrix
(
graph
,
weight
=
)
.
to_dense
(
)
+
1
,
columns
=
list
(
graph
.
nodes
(
)
)
,
index
=
list
(
graph
.
nodes
(
)
)
)
)
)
)
,
columns
=
[
"from"
,
"to"
]
)
results
=
self
.
_run_bnlearn
(
data
,
whitelist
=
whitelist
,
blacklist
=
blacklist
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)

Run the algorithm on an undirected graph .


def orient_directed_graph(self, data, graph):
        """Run the algorithm on a directed_graph.

        Args:
            data (pandas.DataFrame): DataFrame containing the data
            graph (networkx.DiGraph): Skeleton of the graph to orient

        Returns:
            networkx.DiGraph: Solution on the given skeleton.

        .. warning::
           The algorithm is ran on the skeleton of the given graph.

        """
        warnings.warn("The algorithm is ran on the skeleton of the given graph.")
        return self.orient_undirected_graph(data, nx.Graph(graph))


def create_graph_from_data(self, data):
        """Run the algorithm on data.

        Args:
            data (pandas.DataFrame): DataFrame containing the data

        Returns:
            networkx.DiGraph: Solution given by the algorithm.

        """
        # Building setup w/ arguments.
        self.arguments['{SCORE}'] = self.score
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()
        self.arguments['{BETA}'] = str(self.beta)
        self.arguments['{OPTIM}'] = str(self.optim).upper()
        self.arguments['{ALPHA}'] = str(self.alpha)

        results = self._run_bnlearn(data, verbose=self.verbose)
        graph = nx.DiGraph()
        graph.add_edges_from(results)
        return graph

def
create_graph_from_data
(
self
,
data
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{SCORE}'
]
=
self
.
score
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
self
.
arguments
[
'{BETA}'
]
=
str
(
self
.
beta
)
self
.
arguments
[
'{OPTIM}'
]
=
str
(
self
.
optim
)
.
upper
(
)
self
.
arguments
[
'{ALPHA}'
]
=
str
(
self
.
alpha
)
results
=
self
.
_run_bnlearn
(
data
,
verbose
=
self
.
verbose
)
graph
=
nx
.
DiGraph
(
)
graph
.
add_edges_from
(
results
)
return
graph


def computeGaussKernel(x):
    """Compute the gaussian kernel on a 1D vector."""
    xnorm = np.power(euclidean_distances(x, x), 2)
    return np.exp(-xnorm / (2.0))

def computeGaussKernel ( x ) : xnorm = np . power ( euclidean_distances ( x , x ) , 2 ) return np . exp ( - xnorm / ( 2.0 ) )

Compute the gaussian kernel on a 1D vector .


def normal_noise(points):
    """Init a noise variable."""
    return np.random.rand(1) * np.random.randn(points, 1) \
        + random.sample([2, -2], 1)

def normal_noise ( points ) : return np . random . rand ( 1 ) * np . random . randn ( points , 1 ) + random . sample ( [ 2 , - 2 ] , 1 )


def uniform_noise(points):
    """Init a uniform noise variable."""
    return np.random.rand(1) * np.random.uniform(points, 1) \
        + random.sample([2, -2], 1)

def uniform_noise ( points ) : return np . random . rand ( 1 ) * np . random . uniform ( points , 1 ) + random . sample ( [ 2 , - 2 ] , 1 )


def predict_dataset(self, df):
        """Runs Jarfo independently on all pairs.

        Args:
            x (pandas.DataFrame): a CEPC format Dataframe.
            kwargs (dict): additional arguments for the algorithms

        Returns:
            pandas.DataFrame: a Dataframe with the predictions.
        """
        if len(list(df.columns)) == 2:
            df.columns = ["A", "B"]
        if self.model is None:
            raise AssertionError("Model has not been trained before predictions")
        df2 = DataFrame()

        for idx, row in df.iterrows():
            df2 = df2.append(row, ignore_index=True)
            df2 = df2.append({'A': row["B"], 'B': row["A"]}, ignore_index=True)
        return predict.predict(deepcopy(df2), deepcopy(self.model))[::2]


def predict_proba(self, a, b, idx=0, **kwargs):
        """ Use Jarfo to predict the causal direction of a pair of vars.

        Args:
            a (numpy.ndarray): Variable 1
            b (numpy.ndarray): Variable 2
            idx (int): (optional) index number for printing purposes

        Returns:
            float: Causation score (Value : 1 if a->b and -1 if b->a)
        """
        return self.predict_dataset(DataFrame([[a, b]],
                                              columns=['A', 'B']))

def predict_proba ( self , a , b , idx = 0 , * * kwargs ) : return self . predict_dataset ( DataFrame ( [ [ a , b ] ] , columns = [ 'A' , 'B' ] ) )

Use Jarfo to predict the causal direction of a pair of vars .


def clr(M, **kwargs):
    """Implementation of the Context Likelihood or Relatedness Network algorithm.

    Args:
     mat (numpy.ndarray): matrix, if it is a square matrix, the program assumes
         it is a relevance matrix where mat(i,j) represents the similarity content
         between nodes i and j. Elements of matrix should be
         non-negative.

    Returns:
    mat_nd (numpy.ndarray): Output deconvolved matrix (direct dependency matrix). Its components
        represent direct edge weights of observed interactions.

    .. note::
       Ref:Jeremiah J. Faith, Boris Hayete, Joshua T. Thaden, Ilaria Mogno, Jamey
       Wierzbowski, Guillaume Cottarel, Simon Kasif, James J. Collins, and Timothy
       S. Gardner. Large-scale mapping and validation of escherichia coli
       transcriptional regulation from a compendium of expression profiles.
       PLoS Biology, 2007
    """
    R = np.zeros(M.shape)
    Id = [[0, 0] for i in range(M.shape[0])]
    for i in range(M.shape[0]):
        mu_i = np.mean(M[i, :])
        sigma_i = np.std(M[i, :])
        Id[i] = [mu_i, sigma_i]

    for i in range(M.shape[0]):
        for j in range(i + 1, M.shape[0]):
            z_i = np.max([0, (M[i, j] - Id[i][0]) / Id[i][0]])
            z_j = np.max([0, (M[i, j] - Id[j][0]) / Id[j][0]])
            R[i, j] = np.sqrt(z_i**2 + z_j**2)
            R[j, i] = R[i, j]  # Symmetric

    return R

def
clr
(
M
,
*
*
kwargs
)
:
R
=
np
.
zeros
(
M
.
shape
)
Id
=
[
[
0
,
0
]
for
i
in
range
(
M
.
shape
[
0
]
)
]
for
i
in
range
(
M
.
shape
[
0
]
)
:
mu_i
=
np
.
mean
(
M
[
i
,
:
]
)
sigma_i
=
np
.
std
(
M
[
i
,
:
]
)
Id
[
i
]
=
[
mu_i
,
sigma_i
]
for
i
in
range
(
M
.
shape
[
0
]
)
:
for
j
in
range
(
i
+
1
,
M
.
shape
[
0
]
)
:
z_i
=
np
.
max
(
[
0
,
(
M
[
i
,
j
]
Id
[
i
]
[
0
]
)
/
Id
[
i
]
[
0
]
]
)
z_j
=
np
.
max
(
[
0
,
(
M
[
i
,
j
]
Id
[
j
]
[
0
]
)
/
Id
[
j
]
[
0
]
]
)
R
[
i
,
j
]
=
np
.
sqrt
(
z_i
**
2
+
z_j
**
2
)
R
[
j
,
i
]
=
R
[
i
,
j
]
# Symmetric
return
R

Implementation of the Context Likelihood or Relatedness Network algorithm .


def aracne(m, **kwargs):
    """Implementation of the ARACNE algorithm.

    Args:
     mat (numpy.ndarray): matrix, if it is a square matrix, the program assumes
         it is a relevance matrix where mat(i,j) represents the similarity content
         between nodes i and j. Elements of matrix should be
         non-negative.

    Returns:
    mat_nd (numpy.ndarray): Output deconvolved matrix (direct dependency matrix). Its components
        represent direct edge weights of observed interactions.

    .. note::
       Ref: ARACNE: An Algorithm for the Reconstruction of Gene Regulatory Networks in a Mammalian Cellular Context
       Adam A Margolin, Ilya Nemenman, Katia Basso, Chris Wiggins, Gustavo Stolovitzky, Riccardo Dalla Favera and Andrea Califano
       DOI: https://doi.org/10.1186/1471-2105-7-S1-S7
    """
    I0 = kwargs.get('I0', 0.0)  # No default thresholding
    W0 = kwargs.get('W0', 0.05)

    # thresholding
    m = np.where(m > I0, m, 0)

    # Finding triplets and filtering them
    for i in range(m.shape[0]-2):
        for j in range(i+1, m.shape[0]-1):
            for k in range(j+1, m.shape[0]):
                triplet = [m[i, j], m[j, k], m[i, k]]
                min_index, min_value = min(enumerate(triplet), key=operator.itemgetter(1))
                if 0 < min_value < W0:
                    if min_index == 0:
                        m[i, j] = m[j, i] = 0.
                    elif min_index == 1:
                        m[j, k] = m[k, j] = 0.
                    else:
                        m[i, k] = m[k, i] = 0.
    return m

def
aracne
(
m
,
*
*
kwargs
)
:
I0
=
kwargs
.
get
(
'I0'
,
0.0
)
# No default thresholding
W0
=
kwargs
.
get
(
'W0'
,
0.05
)
# thresholding
m
=
np
.
where
(
m
>
I0
,
m
,
0
)
# Finding triplets and filtering them
for
i
in
range
(
m
.
shape
[
0
]
2
)
:
for
j
in
range
(
i
+
1
,
m
.
shape
[
0
]
1
)
:
for
k
in
range
(
j
+
1
,
m
.
shape
[
0
]
)
:
triplet
=
[
m
[
i
,
j
]
,
m
[
j
,
k
]
,
m
[
i
,
k
]
]
min_index
,
min_value
=
min
(
enumerate
(
triplet
)
,
key
=
operator
.
itemgetter
(
1
)
)
if
0
<
min_value
<
W0
:
if
min_index
==
0
:
m
[
i
,
j
]
=
m
[
j
,
i
]
=
0.
elif
min_index
==
1
:
m
[
j
,
k
]
=
m
[
k
,
j
]
=
0.
else
:
m
[
i
,
k
]
=
m
[
k
,
i
]
=
0.
return
m

Implementation of the ARACNE algorithm .


def remove_indirect_links(g, alg="aracne", **kwargs):
    """Apply deconvolution to a networkx graph.

    Args:
       g (networkx.Graph): Graph to apply deconvolution to
       alg (str): Algorithm to use ('aracne', 'clr', 'nd')
       kwargs (dict): extra options for algorithms

    Returns:
       networkx.Graph: graph with undirected links removed.
    """
    alg = {"aracne": aracne,
           "nd": network_deconvolution,
           "clr": clr}[alg]
    mat = np.array(nx.adjacency_matrix(g).todense())
    return nx.relabel_nodes(nx.DiGraph(alg(mat, **kwargs)),
                            {idx: i for idx, i in enumerate(list(g.nodes()))})

def remove_indirect_links ( g , alg = "aracne" , * * kwargs ) : alg = { "aracne" : aracne , "nd" : network_deconvolution , "clr" : clr } [ alg ] mat = np . array ( nx . adjacency_matrix ( g ) . todense ( ) ) return nx . relabel_nodes ( nx . DiGraph ( alg ( mat , * * kwargs ) ) , { idx : i for idx , i in enumerate ( list ( g . nodes ( ) ) ) } )

Apply deconvolution to a networkx graph .


def dagify_min_edge(g):
    """Input a graph and output a DAG.

    The heuristic is to reverse the edge with the lowest score of the cycle
    if possible, else remove it.

    Args:
        g (networkx.DiGraph): Graph to modify to output a DAG

    Returns:
        networkx.DiGraph: DAG made out of the input graph.
    """
    while not nx.is_directed_acyclic_graph(g):
        cycle = next(nx.simple_cycles(g))
        scores = []
        edges = []
        for i, j in zip(cycle[:1], cycle[:1]):
            edges.append((i, j))
            scores.append(g[i][j]['weight'])

        i, j = edges[scores.index(min(scores))]
        gc = deepcopy(g)
        gc.remove_edge(i, j)
        gc.add_edge(j, i)

        if len(list(nx.simple_cycles(gc))) < len(list(nx.simple_cycles(g))):
            g.add_edge(j, i, weight=min(scores))
        g.remove_edge(i, j)
    return g

def dagify_min_edge ( g ) : while not nx . is_directed_acyclic_graph ( g ) : cycle = next ( nx . simple_cycles ( g ) ) scores = [ ] edges = [ ] for i , j in zip ( cycle [ : 1 ] , cycle [ : 1 ] ) : edges . append ( ( i , j ) ) scores . append ( g [ i ] [ j ] [ 'weight' ] ) i , j = edges [ scores . index ( min ( scores ) ) ] gc = deepcopy ( g ) gc . remove_edge ( i , j ) gc . add_edge ( j , i ) if len ( list ( nx . simple_cycles ( gc ) ) ) < len ( list ( nx . simple_cycles ( g ) ) ) : g . add_edge ( j , i , weight = min ( scores ) ) g . remove_edge ( i , j ) return g


def weighted_mean_and_std(values, weights):
    """
    Returns the weighted average and standard deviation.

    values, weights -- numpy ndarrays with the same shape.
    """
    average = np.average(values, weights=weights, axis=0)
    variance = np.dot(weights, (values - average) ** 2) / weights.sum()  # Fast and numerically precise
    return (average, np.sqrt(variance))

def
weighted_mean_and_std
(
values
,
weights
)
:
average
=
np
.
average
(
values
,
weights
=
weights
,
axis
=
0
)
variance
=
np
.
dot
(
weights
,
(
values
average
)
**
2
)
/
weights
.
sum
(
)
# Fast and numerically precise
return
(
average
,
np
.
sqrt
(
variance
)
)

Returns the weighted average and standard deviation .


def GNN_instance(x, idx=0, device=None, nh=20, **kwargs):
    """Run an instance of GNN, testing causal direction.

    :param m: data corresponding to the config : (N, 2) data, [:, 0] cause and [:, 1] effect
    :param pair_idx: print purposes
    :param run: numner of the run (for GPU dispatch)
    :param device: device on with the algorithm is going to be run on.
    :return:
    """
    device = SETTINGS.get_default(device=device)
    xy = scale(x).astype('float32')
    inputx = th.FloatTensor(xy[:, [0]]).to(device)
    target = th.FloatTensor(xy[:, [1]]).to(device)
    GNNXY = GNN_model(x.shape[0], device=device, nh=nh).to(device)
    GNNYX = GNN_model(x.shape[0], device=device, nh=nh).to(device)
    GNNXY.reset_parameters()
    GNNYX.reset_parameters()
    XY = GNNXY.run(inputx, target, **kwargs)
    YX = GNNYX.run(target, inputx, **kwargs)

    return [XY, YX]

def GNN_instance ( x , idx = 0 , device = None , nh = 20 , * * kwargs ) : device = SETTINGS . get_default ( device = device ) xy = scale ( x ) . astype ( 'float32' ) inputx = th . FloatTensor ( xy [ : , [ 0 ] ] ) . to ( device ) target = th . FloatTensor ( xy [ : , [ 1 ] ] ) . to ( device ) GNNXY = GNN_model ( x . shape [ 0 ] , device = device , nh = nh ) . to ( device ) GNNYX = GNN_model ( x . shape [ 0 ] , device = device , nh = nh ) . to ( device ) GNNXY . reset_parameters ( ) GNNYX . reset_parameters ( ) XY = GNNXY . run ( inputx , target , * * kwargs ) YX = GNNYX . run ( target , inputx , * * kwargs ) return [ XY , YX ]

Run an instance of GNN testing causal direction .


def forward(self, x):
        """Pass data through the net structure.

        :param x: input data: shape (:,1)
        :type x: torch.Variable
        :return: output of the shallow net
        :rtype: torch.Variable

        """
        self.noise.normal_()
        return self.layers(th.cat([x, self.noise], 1))

def forward ( self , x ) : self . noise . normal_ ( ) return self . layers ( th . cat ( [ x , self . noise ] , 1 ) )


def run(self, x, y, lr=0.01, train_epochs=1000, test_epochs=1000, idx=0, verbose=None, **kwargs):
        """Run the GNN on a pair x,y of FloatTensor data."""
        verbose = SETTINGS.get_default(verbose=verbose)
        optim = th.optim.Adam(self.parameters(), lr=lr)
        running_loss = 0
        teloss = 0

        for i in range(train_epochs + test_epochs):
            optim.zero_grad()
            pred = self.forward(x)
            loss = self.criterion(pred, y)
            running_loss += loss.item()

            if i < train_epochs:
                loss.backward()
                optim.step()
            else:
                teloss += running_loss

            # print statistics
            if verbose and not i % 300:
                print('Idx:{}; epoch:{}; score:{}'.
                      format(idx, i, running_loss/300))
                running_loss = 0.0

        return teloss / test_epochs

def
run
(
self
,
x
,
y
,
lr
=
0.01
,
train_epochs
=
1000
,
test_epochs
=
1000
,
idx
=
0
,
verbose
=
,
*
*
kwargs
)
:
verbose
=
SETTINGS
.
get_default
(
verbose
=
verbose
)
optim
=
th
.
optim
.
Adam
(
self
.
parameters
(
)
,
lr
=
lr
)
running_loss
=
0
teloss
=
0
for
i
in
range
(
train_epochs
+
test_epochs
)
:
optim
.
zero_grad
(
)
pred
=
self
.
forward
(
x
)
loss
=
self
.
criterion
(
pred
,
y
)
running_loss
+=
loss
.
item
(
)
if
i
<
train_epochs
:
loss
.
backward
(
)
optim
.
step
(
)
else
:
teloss
+=
running_loss
# print statistics
if
verbose
and
not
i
%
300
:
print
(
'Idx:{}; epoch:{}; score:{}'
.
format
(
idx
,
i
,
running_loss
/
300
)
)
running_loss
=
0.0
return
teloss
/
test_epochs

Run the GNN on a pair x y of FloatTensor data .


def predict_proba(self, a, b, nb_runs=6, nb_jobs=None, gpu=None,
                      idx=0, verbose=None, ttest_threshold=0.01,
                      nb_max_runs=16, train_epochs=1000, test_epochs=1000):
        """Run multiple times GNN to estimate the causal direction.

        Args:
            a (np.ndarray): Variable 1
            b (np.ndarray): Variable 2
            nb_runs (int): number of runs to execute per batch (before testing for significance with t-test).
            nb_jobs (int): number of runs to execute in parallel. (Initialized with ``cdt.SETTINGS.NB_JOBS``)
            gpu (bool): use gpu (Initialized with ``cdt.SETTINGS.GPU``)
            idx (int): (optional) index of the pair, for printing purposes
            verbose (bool): verbosity (Initialized with ``cdt.SETTINGS.verbose``)
            ttest_threshold (float): threshold to stop the boostraps before ``nb_max_runs`` if the difference is significant
            nb_max_runs (int): Max number of bootstraps
            train_epochs (int): Number of epochs during which the model is going to be trained
            test_epochs (int): Number of epochs during which the model is going to be tested

        Returns:
            float: Causal score of the pair (Value : 1 if a->b and -1 if b->a)
        """
        Nb_jobs, verbose, gpu = SETTINGS.get_default(('nb_jobs', nb_jobs), ('verbose', verbose), ('gpu', gpu))
        x = np.stack([a.ravel(), b.ravel()], 1)
        ttest_criterion = TTestCriterion(
            max_iter=nb_max_runs, runs_per_iter=nb_runs, threshold=ttest_threshold)

        AB = []
        BA = []

        while ttest_criterion.loop(AB, BA):
            if nb_jobs != 1:
                result_pair = Parallel(n_jobs=nb_jobs)(delayed(GNN_instance)(
                    x, idx=idx, device='cuda:{}'.format(run % gpu) if gpu else 'cpu',
                    verbose=verbose, train_epochs=train_epochs, test_epochs=test_epochs) for run in range(ttest_criterion.iter, ttest_criterion.iter + nb_runs))
            else:
                result_pair = [GNN_instance(x, idx=idx,
                                            device='cuda:0' if gpu else 'cpu',
                                            verbose=verbose,
                                            train_epochs=train_epochs,
                                            test_epochs=test_epochs)
                               for run in range(ttest_criterion.iter, ttest_criterion.iter + nb_runs)]
            AB.extend([runpair[0] for runpair in result_pair])
            BA.extend([runpair[1] for runpair in result_pair])

        if verbose:
            print("P-value after {} runs : {}".format(ttest_criterion.iter,
                                                      ttest_criterion.p_value))

        score_AB = np.mean(AB)
        score_BA = np.mean(BA)

        return (score_BA - score_AB) / (score_BA + score_AB)

def
predict_proba
(
self
,
a
,
b
,
nb_runs
=
6
,
nb_jobs
=
,
gpu
=
,
idx
=
0
,
verbose
=
,
ttest_threshold
=
0.01
,
nb_max_runs
=
16
,
train_epochs
=
1000
,
test_epochs
=
1000
)
:
Nb_jobs
,
verbose
,
gpu
=
SETTINGS
.
get_default
(
(
'nb_jobs'
,
nb_jobs
)
,
(
'verbose'
,
verbose
)
,
(
'gpu'
,
gpu
)
)
x
=
np
.
stack
(
[
a
.
ravel
(
)
,
b
.
ravel
(
)
]
,
1
)
ttest_criterion
=
TTestCriterion
(
max_iter
=
nb_max_runs
,
runs_per_iter
=
nb_runs
,
threshold
=
ttest_threshold
)
AB
=
[
]
BA
=
[
]
while
ttest_criterion
.
loop
(
AB
,
BA
)
:
if
nb_jobs
!=
1
:
result_pair
=
Parallel
(
n_jobs
=
nb_jobs
)
(
delayed
(
GNN_instance
)
(
x
,
idx
=
idx
,
device
=
'cuda:{}'
.
format
(
run
%
gpu
)
if
gpu
else
'cpu'
,
verbose
=
verbose
,
train_epochs
=
train_epochs
,
test_epochs
=
test_epochs
)
for
run
in
range
(
ttest_criterion
.
iter
,
ttest_criterion
.
iter
+
nb_runs
)
)
else
:
result_pair
=
[
GNN_instance
(
x
,
idx
=
idx
,
device
=
'cuda:0'
if
gpu
else
'cpu'
,
verbose
=
verbose
,
train_epochs
=
train_epochs
,
test_epochs
=
test_epochs
)
for
run
in
range
(
ttest_criterion
.
iter
,
ttest_criterion
.
iter
+
nb_runs
)
]
AB
.
extend
(
[
runpair
[
0
]
for
runpair
in
result_pair
]
)
BA
.
extend
(
[
runpair
[
1
]
for
runpair
in
result_pair
]
)
if
verbose
:
print
(
"P-value after {} runs : {}"
.
format
(
ttest_criterion
.
iter
,
ttest_criterion
.
p_value
)
)
score_AB
=
np
.
mean
(
AB
)
score_BA
=
np
.
mean
(
BA
)
return
(
score_BA
score_AB
)
/
(
score_BA
+
score_AB
)

Run multiple times GNN to estimate the causal direction .


def create_graph_from_data(self, data, **kwargs):
        """Apply causal discovery on observational data using CAM.

        Args:
            data (pandas.DataFrame): DataFrame containing the data

        Returns:
            networkx.DiGraph: Solution given by the CAM algorithm.
        """
        # Building setup w/ arguments.
        self.arguments['{SCORE}'] = self.scores[self.score]
        self.arguments['{CUTOFF}'] = str(self.cutoff)
        self.arguments['{VARSEL}'] = str(self.variablesel).upper()
        self.arguments['{SELMETHOD}'] = self.var_selection[self.selmethod]
        self.arguments['{PRUNING}'] = str(self.pruning).upper()
        self.arguments['{PRUNMETHOD}'] = self.var_selection[self.prunmethod]
        self.arguments['{NJOBS}'] = str(self.nb_jobs)
        self.arguments['{VERBOSE}'] = str(self.verbose).upper()
        results = self._run_cam(data, verbose=self.verbose)

        return nx.relabel_nodes(nx.DiGraph(results),
                                {idx: i for idx, i in enumerate(data.columns)})

def
create_graph_from_data
(
self
,
data
,
*
*
kwargs
)
:
# Building setup w/ arguments.
self
.
arguments
[
'{SCORE}'
]
=
self
.
scores
[
self
.
score
]
self
.
arguments
[
'{CUTOFF}'
]
=
str
(
self
.
cutoff
)
self
.
arguments
[
'{VARSEL}'
]
=
str
(
self
.
variablesel
)
.
upper
(
)
self
.
arguments
[
'{SELMETHOD}'
]
=
self
.
var_selection
[
self
.
selmethod
]
self
.
arguments
[
'{PRUNING}'
]
=
str
(
self
.
pruning
)
.
upper
(
)
self
.
arguments
[
'{PRUNMETHOD}'
]
=
self
.
var_selection
[
self
.
prunmethod
]
self
.
arguments
[
'{NJOBS}'
]
=
str
(
self
.
nb_jobs
)
self
.
arguments
[
'{VERBOSE}'
]
=
str
(
self
.
verbose
)
.
upper
(
)
results
=
self
.
_run_cam
(
data
,
verbose
=
self
.
verbose
)
return
nx
.
relabel_nodes
(
nx
.
DiGraph
(
results
)
,
{
idx
:
i
for
idx
,
i
in
enumerate
(
data
.
columns
)
}
)

Apply causal discovery on observational data using CAM .


def forward(self, x):
        """Passing data through the network.

        :param x: 2d tensor containing both (x,y) Variables
        :return: output of the net
        """

        features = self.conv(x).mean(dim=2)
        return self.dense(features)

def forward ( self , x ) : features = self . conv ( x ) . mean ( dim = 2 ) return self . dense ( features )


def predict_proba(self, a, b, device=None):
        """Infer causal directions using the trained NCC pairwise model.

        Args:
            a (numpy.ndarray): Variable 1
            b (numpy.ndarray): Variable 2
            device (str): Device to run the algorithm on (defaults to ``cdt.SETTINGS.default_device``)

        Returns:
            float: Causation score (Value : 1 if a->b and -1 if b->a)
        """
        device = SETTINGS.get_default(device=device)
        if self.model is None:
            print('Model has to be trained before doing any predictions')
            raise ValueError
        if len(np.array(a).shape) == 1:
            a = np.array(a).reshape((-1, 1))
            b = np.array(b).reshape((-1, 1))
        m = np.hstack((a, b))
        m = scale(m)
        m = m.astype('float32')
        m = th.from_numpy(m).t().unsqueeze(0)

        if th.cuda.is_available():
            m = m.cuda()

        return (self.model(m).data.cpu().numpy()-.5) * 2

Infer causal directions using the trained NCC pairwise model .


def phrase_to_filename(self, phrase):
        """Convert phrase to normilized file name."""
        # remove non-word characters
        name = re.sub(r"[^\w\s\.]", '', phrase.strip().lower())
        # replace whitespace with underscores
        name = re.sub(r"\s+", '_', name)

        return name + '.png'

def
phrase_to_filename
(
self
,
phrase
)
:
# remove non-word characters
name
=
re
.
sub
(
r"[^\w\s\.]"
,
''
,
phrase
.
strip
(
)
.
lower
(
)
)
# replace whitespace with underscores
name
=
re
.
sub
(
r"\s+"
,
'_'
,
name
)
return
name
+
'.png'

Convert phrase to normilized file name .


def seed_url(self):
        """A URL that can be used to open the page.

        The URL is formatted from :py:attr:`URL_TEMPLATE`, which is then
        appended to :py:attr:`base_url` unless the template results in an
        absolute URL.

        :return: URL that can be used to open the page.
        :rtype: str

        """
        url = self.base_url
        if self.URL_TEMPLATE is not None:
            url = urlparse.urljoin(
                self.base_url, self.URL_TEMPLATE.format(**self.url_kwargs)
            )

        if not url:
            return None

        url_parts = list(urlparse.urlparse(url))
        query = urlparse.parse_qsl(url_parts[4])

        for k, v in self.url_kwargs.items():
            if v is None:
                continue
            if "{{{}}}".format(k) not in str(self.URL_TEMPLATE):
                for i in iterable(v):
                    query.append((k, i))

        url_parts[4] = urlencode(query)
        return urlparse.urlunparse(url_parts)

def seed_url ( self ) : url = self . base_url if self . URL_TEMPLATE is not None : url = urlparse . urljoin ( self . base_url , self . URL_TEMPLATE . format ( * * self . url_kwargs ) ) if not url : return None url_parts = list ( urlparse . urlparse ( url ) ) query = urlparse . parse_qsl ( url_parts [ 4 ] ) for k , v in self . url_kwargs . items ( ) : if v is None : continue if "{{{}}}" . format ( k ) not in str ( self . URL_TEMPLATE ) : for i in iterable ( v ) : query . append ( ( k , i ) ) url_parts [ 4 ] = urlencode ( query ) return urlparse . urlunparse ( url_parts )

A URL that can be used to open the page .


def open(self):
        """Open the page.

        Navigates to :py:attr:`seed_url` and calls :py:func:`wait_for_page_to_load`.

        :return: The current page object.
        :rtype: :py:class:`Page`
        :raises: UsageError

        """
        if self.seed_url:
            self.driver_adapter.open(self.seed_url)
            self.wait_for_page_to_load()
            return self
        raise UsageError("Set a base URL or URL_TEMPLATE to open this page.")


def wait_for_page_to_load(self):
        """Wait for the page to load."""
        self.wait.until(lambda _: self.loaded)
        self.pm.hook.pypom_after_wait_for_page_to_load(page=self)
        return self

def wait_for_page_to_load ( self ) : self . wait . until ( lambda _ : self . loaded ) self . pm . hook . pypom_after_wait_for_page_to_load ( page = self ) return self


def register():
    """ Register the Selenium specific driver implementation.

        This register call is performed by the init module if
        selenium is available.
    """
    registerDriver(
        ISelenium,
        Selenium,
        class_implements=[
            Firefox,
            Chrome,
            Ie,
            Edge,
            Opera,
            Safari,
            BlackBerry,
            PhantomJS,
            Android,
            Remote,
            EventFiringWebDriver,
        ],
    )

def register ( ) : registerDriver ( ISelenium , Selenium , class_implements = [ Firefox , Chrome , Ie , Edge , Opera , Safari , BlackBerry , PhantomJS , Android , Remote , EventFiringWebDriver , ] , )

Register the Selenium specific driver implementation .


def root(self):
        """Root element for the page region.

        Page regions should define a root element either by passing this on
        instantiation or by defining a :py:attr:`_root_locator` attribute. To
        reduce the chances of hitting :py:class:`~selenium.common.exceptions.StaleElementReferenceException`
        or similar you should use :py:attr:`_root_locator`, as this is looked up every
        time the :py:attr:`root` property is accessed.
        """
        if self._root is None and self._root_locator is not None:
            return self.page.find_element(*self._root_locator)
        return self._root

def root ( self ) : if self . _root is None and self . _root_locator is not None : return self . page . find_element ( * self . _root_locator ) return self . _root


def wait_for_region_to_load(self):
        """Wait for the page region to load."""
        self.wait.until(lambda _: self.loaded)
        self.pm.hook.pypom_after_wait_for_region_to_load(region=self)
        return self

def wait_for_region_to_load ( self ) : self . wait . until ( lambda _ : self . loaded ) self . pm . hook . pypom_after_wait_for_region_to_load ( region = self ) return self


def find_element(self, strategy, locator):
        """Finds an element on the page.

        :param strategy: Location strategy to use. See :py:class:`~selenium.webdriver.common.by.By` or :py:attr:`~pypom.splinter_driver.ALLOWED_STRATEGIES`.
        :param locator: Location of target element.
        :type strategy: str
        :type locator: str
        :return: An element.
        :rytpe: :py:class:`~selenium.webdriver.remote.webelement.WebElement` or :py:class:`~splinter.driver.webdriver.WebDriverElement`

        """
        return self.driver_adapter.find_element(strategy, locator, root=self.root)

def find_element ( self , strategy , locator ) : return self . driver_adapter . find_element ( strategy , locator , root = self . root )


def find_elements(self, strategy, locator):
        """Finds elements on the page.

        :param strategy: Location strategy to use. See :py:class:`~selenium.webdriver.common.by.By` or :py:attr:`~pypom.splinter_driver.ALLOWED_STRATEGIES`.
        :param locator: Location of target elements.
        :type strategy: str
        :type locator: str
        :return: List of :py:class:`~selenium.webdriver.remote.webelement.WebElement` or :py:class:`~splinter.element_list.ElementList`
        :rtype: list

        """
        return self.driver_adapter.find_elements(strategy, locator, root=self.root)

def find_elements ( self , strategy , locator ) : return self . driver_adapter . find_elements ( strategy , locator , root = self . root )


def is_element_present(self, strategy, locator):
        """Checks whether an element is present.

        :param strategy: Location strategy to use. See :py:class:`~selenium.webdriver.common.by.By` or :py:attr:`~pypom.splinter_driver.ALLOWED_STRATEGIES`.
        :param locator: Location of target element.
        :type strategy: str
        :type locator: str
        :return: ``True`` if element is present, else ``False``.
        :rtype: bool

        """
        return self.driver_adapter.is_element_present(strategy, locator, root=self.root)

def is_element_present ( self , strategy , locator ) : return self . driver_adapter . is_element_present ( strategy , locator , root = self . root )


def is_element_displayed(self, strategy, locator):
        """Checks whether an element is displayed.

        :param strategy: Location strategy to use. See :py:class:`~selenium.webdriver.common.by.By` or :py:attr:`~pypom.splinter_driver.ALLOWED_STRATEGIES`.
        :param locator: Location of target element.
        :type strategy: str
        :type locator: str
        :return: ``True`` if element is displayed, else ``False``.
        :rtype: bool

        """
        return self.driver_adapter.is_element_displayed(
            strategy, locator, root=self.root
        )

def is_element_displayed ( self , strategy , locator ) : return self . driver_adapter . is_element_displayed ( strategy , locator , root = self . root )

Checks whether an element is displayed .


def registerDriver(iface, driver, class_implements=[]):
    """ Register driver adapter used by page object"""
    for class_item in class_implements:
        classImplements(class_item, iface)

    component.provideAdapter(factory=driver, adapts=[iface], provides=IDriver)

def registerDriver ( iface , driver , class_implements = [ ] ) : for class_item in class_implements : classImplements ( class_item , iface ) component . provideAdapter ( factory = driver , adapts = [ iface ] , provides = IDriver )


def t_intnumber(self, t):
        r'-?\d+'
        t.value = int(t.value)
        t.type = 'NUMBER'
        return t

def t_intnumber ( self , t ) : t . value = int ( t . value ) t . type = 'NUMBER' return t


def t_stringdollar_rbrace(self, t):
        r'\}'
        t.lexer.braces -= 1

        if t.lexer.braces == 0:
            # End of the dollar brace, back to the rest of the string
            t.lexer.begin('string')


def t_tabbedheredoc(self, t):
        r'<<-\S+\r?\n'
        t.lexer.is_tabbed = True
        self._init_heredoc(t)
        t.lexer.begin('tabbedheredoc')

def t_tabbedheredoc ( self , t ) : t . lexer . is_tabbed = True self . _init_heredoc ( t ) t . lexer . begin ( 'tabbedheredoc' )


def t_heredoc(self, t):
        r'<<\S+\r?\n'
        t.lexer.is_tabbed = False
        self._init_heredoc(t)
        t.lexer.begin('heredoc')

def t_heredoc ( self , t ) : t . lexer . is_tabbed = False self . _init_heredoc ( t ) t . lexer . begin ( 'heredoc' )


def _pre_install():
    '''Initialize the parse table at install time'''

    # Generate the parsetab.dat file at setup time
    dat = join(setup_dir, 'src', 'hcl', 'parsetab.dat')
    if exists(dat):
        os.unlink(dat)

    sys.path.insert(0, join(setup_dir, 'src'))

    import hcl
    from hcl.parser import HclParser

    parser = HclParser()


def append(self, linenumber, raw_text, cells):
        """Add another row of data from a test suite"""
        self.rows.append(Row(linenumber, raw_text, cells))

def append ( self , linenumber , raw_text , cells ) : self . rows . append ( Row ( linenumber , raw_text , cells ) )


def RobotFactory(path, parent=None):
    '''Return an instance of SuiteFile, ResourceFile, SuiteFolder

    Exactly which is returned depends on whether it's a file or
    folder, and if a file, the contents of the file. If there is a
    testcase table, this will return an instance of SuiteFile,
    otherwise it will return an instance of ResourceFile.
    '''

    if os.path.isdir(path):
        return SuiteFolder(path, parent)

    else:
        rf = RobotFile(path, parent)

        for table in rf.tables:
            if isinstance(table, TestcaseTable):
                rf.__class__ = SuiteFile
                return rf

        rf.__class__ = ResourceFile
        return rf

def RobotFactory ( path , parent = None ) : if os . path . isdir ( path ) : return SuiteFolder ( path , parent ) else : rf = RobotFile ( path , parent ) for table in rf . tables : if isinstance ( table , TestcaseTable ) : rf . __class__ = SuiteFile return rf rf . __class__ = ResourceFile return rf

Return an instance of SuiteFile ResourceFile SuiteFolder