int getNumberOfConnectedSynapses(Neuron neuron) {
   int numberOfConnectedSynapses = 0;
   for (DistalSegment distalSegment : neuron.getDistalSegments()) {
     numberOfConnectedSynapses += distalSegment.getConnectedSynapses().size();
   }
   return numberOfConnectedSynapses;
 }
 int getNumberOfConnectedSynapsesToCurrentActiveNeuron(
     Neuron possiblyActiveInNextTimeStep, Neuron activeNeuron) {
   // NOTE: This is incredibly inefficient. Fix this by making activeNeuron
   // know which synapses from which neurons are connected to it.
   int numberOfConnectedSynapsesToCurrentActiveNeuron = 0;
   for (DistalSegment distalSegment : possiblyActiveInNextTimeStep.getDistalSegments()) {
     for (Synapse synapse : distalSegment.getConnectedSynapses()) {
       if (synapse.getCell().equals(activeNeuron)) {
         numberOfConnectedSynapsesToCurrentActiveNeuron++;
       }
     }
   }
   return numberOfConnectedSynapsesToCurrentActiveNeuron;
 }
  /**
   * Call this method to run PredictionAlgorithm_1 once on a Region.
   *
   * <p>MAIN LOGIC: For each learning neuron in an active column, connect to all previously active
   * neurons.
   */
  public void run() {
    // Step 1) Which neurons to apply logic to?
    // POSSIBLE ANSWER: Iterate through all neurons in active columns in region
    Set<ColumnPosition> activeColumnPositions = this.spatialPooler.getActiveColumnPositions();
    for (ColumnPosition ACP : activeColumnPositions) {
      Column activeColumn = super.getRegion().getColumn(ACP.getRow(), ACP.getRow());
      Neuron learningNeuron = this.getNeuronWithLeastNumberOfConnectedSynapses(activeColumn);

      // Step 2) How do you allow neuronA to predict neuronB will become
      // active in the next time step?
      // POSSIBLE ANSWER: For each learning neuron connect to all
      // previously active neurons. 1 new distal segment per learning neuron.
      DistalSegment distalSegment = new DistalSegment();

      for (Neuron previouslyActiveNeuron : this.wasActiveNeurons) {
        distalSegment.addSynapse(
            new Synapse<>(previouslyActiveNeuron, Synapse.MINIMAL_CONNECTED_PERMANENCE, -1, -1));
      }
      learningNeuron.addDistalSegment(distalSegment);

      // Step 3) Which neurons should be active for the current time step?
      // POSSIBLE ANSWER: The active neurons that best represent the
      //                  current sensory input.
      //                                      2
      // EXAMPLE: Imagine you saw "2 - 1" and - . Although the minus
      //                                      1
      //          symbol can also represent division you are not confused
      //          because the "2" and "1" are in different locations.
      //          Your brain saw the "2" and "1" SDRs as well as the SDR
      //          for how your eye moved while looking at "2", "1", and
      //          "-" in sequence so when you saw "-" you knew that it
      //          meant minus or division.
      //
      // CONCLUSION: We want the current SDR to be the active neurons that
      //             are most connected to all previous active SDRs. In
      //             this case it includes vision and eye muscle SDRs.
      Neuron activeNeuron = this.computeActiveNeuron(activeColumn);
      activeNeuron.setActiveState(true);
      this.isActiveNeurons.add(activeNeuron);
    }

    // Step 4) What neurons can be used for prediction?
    // POSSIBLE ANSWER: which neurons currently have the most # of connected
    // (NOT active Cells)
    // synapses across all distal dendrites connected to the current set of
    // active neurons. This is where we reward all the competition between
    // all synapses to represent an connection to a past time step.

    // NOTE: connectionScores = sorted # of connected synapses for each neuron in Region
    Set<Integer> connectionScores = this.getConnectionScores();

    int index =
        Math.max(0, connectionScores.size() - this.spatialPooler.getActiveColumnPositions().size());
    int minimumConnectionScore = (Integer) connectionScores.toArray()[index];

    // Step 5) How many number of predicting neurons?
    // POSSIBLE ANSWER: same number of currently active neurons.
    this.updateIsPredictingNeurons(minimumConnectionScore);

    // Step 6) Which synapse connections should be strengthened to model
    // long term potentiation?
    // POSSIBLE ANSWER: Current time-step is @t=4. Strengthen the
    // connection between neuronBs that isActive @t=4 and isPredicting
    // @t=3 and neuronA that isActive @t=3.
    for (Neuron activeNeuronBatTequals4 : this.isActiveNeurons) {
      if (activeNeuronBatTequals4.getPreviousPredictingState()) {

        for (DistalSegment distalSegment : activeNeuronBatTequals4.getDistalSegments()) {
          for (Synapse synapse : distalSegment.getSynapses()) {
            // increase permanence of connection with
            // neuronAs' active @t=3.
            if (synapse.getCell().getPreviousActiveState()) {
              synapse.increasePermanence();
            }
          }
        }
      }
    }

    // Step 7) Which synapse connections should be weakened to model
    // long term depression?
    // POSSIBLE ANSWER: Current time-step is @t=4. Weaken the connection
    // between neuronBs that isActive=False @t=4 and isPredicting @t=3
    // and neuronA that isActive @t=3.
    Column[][] columns = super.region.getColumns();
    for (int ri = 0; ri < columns.length; ri++) {
      for (int ci = 0; ci < columns[0].length; ci++) {
        for (Neuron inActiveNeuronBatTequals4 : columns[ri][ci].getNeurons()) {
          if (!inActiveNeuronBatTequals4.getActiveState()
              && inActiveNeuronBatTequals4.getPreviousPredictingState()) {

            for (DistalSegment distalSegment : inActiveNeuronBatTequals4.getDistalSegments()) {
              for (Synapse synapse : distalSegment.getSynapses()) {
                // decrease permanence of connection with
                // neuronA' active @t=3.
                if (synapse.getCell().getPreviousActiveState()) {
                  synapse.decreasePermanence();
                }
              }
            }
          }
        }
      }
    }

    this.nextTimeStep();
  }