'Perform the negative phase.
This method computes the sufficient statistics under the model distribution.
Args:
step: Training step
train: If true, then this computation is happening during training.
gibbs_steps: Number of gibbs steps to take. If -1, use default.'

def NegativePhase(self, step=0, train=True, gibbs_steps=(-1)):

    losses = []
    if self.cd:
        for node in self.node_list:
            if (not node.is_input):
                node.Sample()
    else:
        for node in self.layer:
            self.SetPhase(node, pos=False)
    if (gibbs_steps < 0):
        h = self.net.hyperparams
        start_after = h.start_step_up_cd_after
        if ((start_after > 0) and (start_after < step)):
            gibbs_steps = ((h.gibbs_steps + 1) + ((step - start_after) / h.step_up_cd_after))
        else:
            gibbs_steps = h.gibbs_steps
    for i in range(gibbs_steps):
        for node in self.neg_phase_order:
            self.ComputeUp(node, train=train, step=step, maxsteps=self.train_stop_steps, use_samples=True, compute_input=True, neg_phase=True)
            if ((i == 0) and node.is_input and self.cd):
                losses.append(node.GetLoss())
            if node.is_input:
                if (node.sample_input and (node.hyperparams.sample_input_after <= step)):
                    node.Sample()
                else:
                    node.sample.assign(node.state)
            else:
                node.Sample()
    if train:
        for node in self.layer:
            node.CollectSufficientStatistics(neg=True)
            self.UpdateLayerParams(node, step=step)
        for edge in self.edge:
            edge.CollectSufficientStatistics(neg=True)
            self.UpdateEdgeParams(edge, step=step)
    if (not self.cd):
        for node in self.layer:
            self.SetPhase(node, pos=True)
    return losses
