Package ca.nengo.util.impl

Source Code of ca.nengo.util.impl.NEFGPUInterface$NetworkArrayData

package ca.nengo.util.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import ca.nengo.math.impl.MultiLevelKLNetworkPartitioner;
import ca.nengo.model.Node;
import ca.nengo.model.Origin;
import ca.nengo.model.PlasticNodeTermination;
import ca.nengo.model.Projection;
import ca.nengo.model.RealOutput;
import ca.nengo.model.SimulationMode;
import ca.nengo.model.Termination;
import ca.nengo.model.Units;
import ca.nengo.model.impl.EnsembleTermination;
import ca.nengo.model.impl.NetworkArrayImpl;
import ca.nengo.model.impl.NetworkImpl;
import ca.nengo.model.impl.NetworkImpl.OriginWrapper;
import ca.nengo.model.impl.NetworkImpl.TerminationWrapper;
import ca.nengo.model.impl.RealOutputImpl;
import ca.nengo.model.nef.NEFEnsemble;
import ca.nengo.model.nef.impl.DecodedOrigin;
import ca.nengo.model.nef.impl.DecodedTermination;
import ca.nengo.model.nef.impl.NEFEnsembleImpl;
import ca.nengo.model.neuron.impl.LIFSpikeGenerator;
import ca.nengo.model.neuron.impl.SpikingNeuron;

/**
* Allows running NEFEnsembles on the GPU.
* Passes the ensemble data to the GPU through a native function.
* Passes input to the GPU each step and stores the output from the GPU in the appropriate locations.
*
* @author Eric Crawford
*/
public class NEFGPUInterface {
  private static boolean myUseGPU = false;
  private static int myNumDevices = 0;
  private static int myNumDetectedDevices = 0;
  private static String myErrorMessage;
 
  private static boolean showTiming = false;
  private boolean myShowTiming;
  private long averageTimeSpentInGPU;
  private long averageTimeSpentInCPU;
  private long totalRunTime;
  private int numSteps;
 
  protected boolean myRequireAllOutputsOnCPU;
 
  protected NEFEnsembleImpl[] myGPUEnsembles;
  protected Projection[] myGPUProjections;
  protected Projection[] nonGPUProjections;
  protected Node[] myGPUNetworkArrays;
 
  protected Node[] myNodes;
  protected Projection[] myProjections;
 
  protected float myStartTime;
  protected float myEndTime;
 
  float[][][] representedInputValues;
  float[][][] representedOutputValues;
  float[][] spikeOutput;
  boolean[][] inputOnGPU;
 
  /**  Load the shared library that contains the native functions.
   * This is called just once, when this class is initially loaded.
   *
   */
  static{
    try {
      myErrorMessage = "";
      System.loadLibrary("NengoGPU");
      myNumDetectedDevices = nativeGetNumDevices();
     
      if(myNumDetectedDevices < 1)
      {
        myErrorMessage = "No CUDA-enabled GPU detected.";
        System.out.println(myErrorMessage);
      }
     
    } catch (java.lang.UnsatisfiedLinkError e) {
      myNumDetectedDevices = 0;
      myErrorMessage = "Couldn't load native library NengoGPU - Linker error:";
      // System.out.println(myErrorMessage);
      // System.out.println(e);
    } catch (Exception e) {
      myNumDetectedDevices = 0;
      myErrorMessage = "Couldn't load native library NengoGPU - General exception:";
      System.out.println(myErrorMessage);
      System.out.println(e.getMessage());
      System.out.println(e.getStackTrace());
    }
  }

  static native int nativeGetNumDevices();

  static native void nativeSetupRun(float[][][][] terminationTransforms,
      int[][] isDecodedTermination, float[][] terminationTau,
      float[][][] encoders, float[][][][] decoders, float[][] neuronData,
      int[][] projections, int[][] networkArrayData, int[][] ensembleData,
      int[] isSpikingEnsemble, int[] collectSpikes, int[][] outputRequiredOnCPU, float maxTimeStep,
      int[] deviceForNetworkArrays, int numDevicesRequested);

  static native void nativeStep(float[][][] representedInput,
      float[][][] representedOutput, float[][] spikes, float startTime,
      float endTime);

  static native void nativeKill();
 
  public NEFGPUInterface(boolean interactive){
    myRequireAllOutputsOnCPU = interactive;
    }

  public static int getNumDetectedDevices(){
    return myNumDetectedDevices;
  }
 
  public static void setNumDevices(int value){
    myNumDevices = Math.min(Math.max(value, 0), myNumDetectedDevices);
  }
 
  public static int getNumDevices(){
    return myNumDevices;
  }
 
  // get whether or not to use the GPU. set whether or not to use the GPU by using setRequestedNumDevices
  public static boolean getUseGPU(){
    return myNumDevices > 0;
  }
 
  public static void showGPUTiming(){
    showTiming = true;
  }
 
  public static void hideGPUTiming(){
    showTiming = false;
  }
 
  public static String getErrorMessage(){
    return myErrorMessage;
  }
 
  public void setRequireAllOutputsOnCPU(boolean require){
    myRequireAllOutputsOnCPU = require;
  }
 
  /**
   * Gets all the necessary data from the nodes and projections which are assigned to run on GPUss
   * and puts it in a form appropriate for passing to the native setup function. The native setup function
   * will create a thread for each GPU in use, process the data further until its in a form suitable
   * for running on the GPU, and finally move all the data to the GPU. The GPU threads will be waiting
   * for a call to nativeStep which will tell them to take a step.
   *
   * @author Eric Crawford
   */
  public void initialize(){
    int[] nodeAssignments = findOptimalNodeAssignments(myGPUNetworkArrays, myGPUProjections, myNumDevices);

    boolean requireAllOutputsOnCPU = myRequireAllOutputsOnCPU;
   
    myShowTiming = showTiming;
    if(myShowTiming){
      averageTimeSpentInGPU = 0;
      averageTimeSpentInCPU = 0;
      numSteps = 0;
      totalRunTime = 0;
    }
   
    ArrayList<Node> GPUNodeList = new ArrayList<Node>();
   
    for(Node currentNode : myGPUNetworkArrays){
      // all the nodes in myGPUNetworkArrays are going to run on the GPU.
      if(currentNode instanceof NetworkArrayImpl){
        List<Node> nodeList = Arrays.asList(((NetworkImpl) currentNode).getNodes());
        GPUNodeList.addAll(nodeList);
      }
      else{
        GPUNodeList.add(currentNode);
      }
    }
   
    myGPUEnsembles = GPUNodeList.toArray(new NEFEnsembleImpl[0]);

    if (myGPUEnsembles.length == 0)
      return;

    // Put the data in a format appropriate for passing to the GPU.
    // Most of this function is devoted to this task.
    int i = 0, j = 0, k = 0, numEnsemblesCollectingSpikes = 0;
    NEFEnsemble workingNode;
    Termination[] terminations;
    DecodedOrigin[] origins;

    float[][][][] terminationTransforms = new float[myGPUEnsembles.length][][][];
    int[][] isDecodedTermination = new int[myGPUEnsembles.length][];
    float[][] terminationTau = new float[myGPUEnsembles.length][];
    float[][][] encoders = new float[myGPUEnsembles.length][][];
    float[][][][] decoders = new float[myGPUEnsembles.length][][][];
    float[][] neuronData = new float[myGPUEnsembles.length][];
    EnsembleData ensembleData = new EnsembleData();
    int[][] ensembleDataArray = new int[myGPUEnsembles.length][];
    int[] collectSpikes = new int[myGPUEnsembles.length];
    int[][] outputRequiredOnCPU = new int[myGPUNetworkArrays.length][];
    int[] isSpikingEnsemble = new int[myGPUEnsembles.length];
    float maxTimeStep = ((LIFSpikeGenerator) ((SpikingNeuron) ((NEFEnsembleImpl) myGPUEnsembles[0])
        .getNodes()[0]).getGenerator()).getMaxTimeStep();
   
   

   
    // We put the list of projections in terms of the GPU nodes
    // For each projection we record 4 numbers: the index of the origin
    // ensemble, the index of the origin in its ensemble, the index of
    // the termination ensemble and the index of the termination in its ensemble
    int[][] adjustedProjections = new int[myGPUProjections.length][6];
   
   
    inputOnGPU = new boolean[myGPUNetworkArrays.length][];
   
    Node workingArray;
    int networkArrayOffset = 0;

    NetworkArrayData networkArrayData = new NetworkArrayData();
    int[][] networkArrayDataArray = new int[myGPUNetworkArrays.length][];

    int totalInputSize = 0;
   
    // store networkArray data
    for(i = 0; i < myGPUNetworkArrays.length; i++){
     
      networkArrayData.reset();
      workingArray = myGPUNetworkArrays[i];
     
      networkArrayData.indexOfFirstNode = networkArrayOffset;
     
      if(workingArray instanceof NEFEnsembleImpl){
        networkArrayOffset++;
      }else{
        networkArrayOffset += ((NetworkImpl) workingArray).getNodes().length;
      }
     
      networkArrayData.endIndex = networkArrayOffset;
       
      Termination[] networkArrayTerminations = workingArray.getTerminations();
      networkArrayData.numTerminations = networkArrayTerminations.length;
     
     
      for(j = 0; j < networkArrayTerminations.length; j++){
        networkArrayData.totalInputSize += networkArrayTerminations[j].getDimensions();
      }
     
      totalInputSize += networkArrayData.totalInputSize;
     
      Origin[] networkArrayOrigins;
      if(workingArray instanceof NEFEnsembleImpl)
      {
        networkArrayOrigins = ((NEFEnsembleImpl) workingArray).getDecodedOrigins();
      }else{
        networkArrayOrigins = workingArray.getOrigins();
      }
      networkArrayData.numOrigins = networkArrayOrigins.length;
     
      for(j = 0; j < networkArrayOrigins.length; j++){
        networkArrayData.totalOutputSize += networkArrayOrigins[j].getDimensions();
      }
     
      if(workingArray instanceof NEFEnsembleImpl){
        networkArrayData.numNeurons = ((NEFEnsembleImpl) workingArray).getNeurons();
      }else{
        Node[] subNodes = ((NetworkImpl) workingArray).getNodes();
        for(j = 0; j < subNodes.length; j++){
          networkArrayData.numNeurons += ((NEFEnsembleImpl) subNodes[j]).getNeurons();
        }
      }

      networkArrayDataArray[i] = networkArrayData.getAsArray();
     
      inputOnGPU[i] = new boolean[networkArrayTerminations.length];
      outputRequiredOnCPU[i] = new int[networkArrayOrigins.length];
     
      for(j = 0; j < networkArrayTerminations.length; j++){
        Termination termination = networkArrayTerminations[j];
        boolean terminationWrapped = termination instanceof TerminationWrapper;
        if(terminationWrapped)
          termination = ((TerminationWrapper) termination).getBaseTermination();
       
        k = 0;
        boolean projectionMatches = false;
       
        while(!projectionMatches && k < myGPUProjections.length){
          Termination projectionTermination = myGPUProjections[k].getTermination();
          boolean projectionTerminationWrapped = projectionTermination instanceof TerminationWrapper;
          if(projectionTerminationWrapped)
            projectionTermination = ((TerminationWrapper) projectionTermination).getBaseTermination();
         
          projectionMatches = termination == projectionTermination;
         
          if(projectionMatches)
            break;
         
          k++;
        }
 
        if (projectionMatches) {
          adjustedProjections[k][2] = i;
          adjustedProjections[k][3] = j;
          adjustedProjections[k][4] = termination.getDimensions();
          adjustedProjections[k][5] = -1;
 
          inputOnGPU[i][j] = true;
        } else {
          inputOnGPU[i][j] = false;
        }
      }
     
      for (j = 0; j < networkArrayOrigins.length; j++) {
        Origin origin = networkArrayOrigins[j];
        boolean originWrapped = origin instanceof OriginWrapper;
        if(originWrapped)
          origin = ((OriginWrapper) origin).getWrappedOrigin();
       
        for (k = 0; k < myGPUProjections.length; k++) {
          Origin projectionOrigin = myGPUProjections[k].getOrigin();
          boolean projectionOriginWrapped = projectionOrigin instanceof OriginWrapper;
         
          if(projectionOriginWrapped)
            projectionOrigin = ((OriginWrapper) projectionOrigin).getWrappedOrigin();
         
          if (origin == projectionOrigin) {
            adjustedProjections[k][0] = i;
            adjustedProjections[k][1] = j;
          }
        }
       
        outputRequiredOnCPU[i][j] = (origin.getRequiredOnCPU() || requireAllOutputsOnCPU) ? 1 : 0;
       
        // even if its not explicitly required on the CPU, it might be implicitly
        // if it is attached to a projection whose termination is on the CPU
        if(outputRequiredOnCPU[i][j] == 0){
            for (k = 0; k < nonGPUProjections.length; k++) {
              Origin projectionOrigin = nonGPUProjections[k].getOrigin();
                        boolean projectionOriginWrapped = projectionOrigin instanceof OriginWrapper;
                       
                        if(projectionOriginWrapped)
                            projectionOrigin = ((OriginWrapper) projectionOrigin).getWrappedOrigin();
                   
                        if (origin == projectionOrigin){
                            outputRequiredOnCPU[i][j] = 1;
                        }
            }
        }
      }
    }
   
    nonGPUProjections = null;
   
    // store NEFEnsemble data
    for (i = 0; i < myGPUEnsembles.length; i++) {
     
      workingNode = myGPUEnsembles[i];
     
      ensembleData.reset();

      ensembleData.dimension = workingNode.getDimension();
      ensembleData.numNeurons = workingNode.getNodeCount();
     
      isSpikingEnsemble[i] = (workingNode.getMode() == SimulationMode.DEFAULT) ? 1 : 0;

      terminations = workingNode.getTerminations();

      int terminationDim = 0;
      ensembleData.maxTransformDimension = 0;

      terminationTransforms[i] = new float[terminations.length][][];
      terminationTau[i] = new float[terminations.length];
      isDecodedTermination[i] = new int[terminations.length];
     
      for (j = 0; j < terminations.length; j++) {

        if (terminations[j] instanceof DecodedTermination) {
          terminationTransforms[i][j] = ((DecodedTermination) terminations[j])
              .getTransform();
          terminationTau[i][j] = terminations[j].getTau();

          terminationDim = terminations[j].getDimensions();
          ensembleData.totalInputSize += terminationDim;

          if (terminationDim > ensembleData.maxTransformDimension) {
            ensembleData.maxTransformDimension = terminationDim;
          }

          isDecodedTermination[i][j] = 1;
         
          ensembleData.numDecodedTerminations++;
        } else if (terminations[j] instanceof EnsembleTermination) {
          terminationTransforms[i][j] = new float[1][1];
         
         
          // when we do learning, this will have to be changed, as well as some code in the NengoGPU library.
          // currently it assumes all neurons in the ensemble have the same weight for each non-decoded termination
          // (mainly just to support gates which have uniform negative weights).
          // When we do learning, will have to extract the whole weight matrix.
          Termination[] neuronTerminations = ((EnsembleTermination) terminations[j]).getNodeTerminations();
          terminationTransforms[i][j][0] = ((PlasticNodeTermination) neuronTerminations[0]).getWeights();
          terminationTau[i][j] = terminations[j].getTau();
          isDecodedTermination[i][j] = 0;

          terminationDim = terminations[j].getDimensions();
         
          ensembleData.totalInputSize += terminationDim;
          ensembleData.nonDecodedTransformSize += terminationDim;
          ensembleData.numNonDecodedTerminations++;
        }
      }

      encoders[i] = workingNode.getEncoders();
      float[] radii = workingNode.getRadii();
      for (j = 0; j < encoders[i].length; j++) {
        for (k = 0; k < encoders[i][j].length; k++)
          encoders[i][j][k] = encoders[i][j][k] / radii[k];
      }

      origins = ((NEFEnsembleImpl) workingNode).getDecodedOrigins();

      ensembleData.numOrigins = origins.length;
      ensembleData.maxDecoderDimension = 0;

      decoders[i] = new float[origins.length][][];
      int originDim;
      for (j = 0; j < origins.length; j++) {
        decoders[i][j] = origins[j].getDecoders();
        originDim = origins[j].getDimensions();

        ensembleData.totalOutputSize += originDim;

        if (originDim > ensembleData.maxDecoderDimension) {
          ensembleData.maxDecoderDimension = originDim;
        }
      }

      neuronData[i] = ((NEFEnsembleImpl) workingNode).getStaticNeuronData();

      //collectSpikes[i] = (workingNode.isCollectingSpikes() || requireAllOutputsOnCPU) ? 1 : 0;
      collectSpikes[i] = workingNode.isCollectingSpikes() ? 1 : 0;
      numEnsemblesCollectingSpikes++;

      ensembleDataArray[i] = ensembleData.getAsArray();
    }
   
    nativeSetupRun(terminationTransforms, isDecodedTermination,
        terminationTau, encoders, decoders, neuronData,
        adjustedProjections, networkArrayDataArray, ensembleDataArray,
        isSpikingEnsemble, collectSpikes, outputRequiredOnCPU, maxTimeStep, nodeAssignments, myNumDevices);

    // Set up the data structures that we pass in and out of the native step call.
    // They do not change in size from step to step so we can re-use them.
    representedInputValues = new float[myGPUNetworkArrays.length][][];
    representedOutputValues = new float[myGPUNetworkArrays.length][][];
    spikeOutput = new float [myGPUEnsembles.length][];
   
    for (i = 0; i < myGPUNetworkArrays.length; i++) {
      terminations = myGPUNetworkArrays[i].getTerminations();
      representedInputValues[i] = new float[terminations.length][];
    }

    for (i = 0; i < myGPUNetworkArrays.length; i++) {
      Origin[] networkArrayOrigins;
      if(myGPUNetworkArrays[i] instanceof NEFEnsembleImpl)
      {
        networkArrayOrigins = ((NEFEnsembleImpl) myGPUNetworkArrays[i]).getDecodedOrigins();
      }else{
        networkArrayOrigins = myGPUNetworkArrays[i].getOrigins();
      }

      representedOutputValues[i] = new float[networkArrayOrigins.length][];

      for (j = 0; j < networkArrayOrigins.length; j++) {
        if(outputRequiredOnCPU[i][j] != 0){
          representedOutputValues[i][j] = new float[networkArrayOrigins[j].getDimensions()];
        }else{
          representedOutputValues[i][j] = null;
        }
      }
    }
   
    for (i = 0; i < myGPUEnsembles.length; i++) {
      if(collectSpikes[i] != 0){
        spikeOutput[i] = new float[myGPUEnsembles[i].getNeurons()];
      }else{
        spikeOutput[i] = null;
      }
    }
  }
 
  /**
   * 1. Load data from terminations into "representedInputValues".
   * 2. Call nativeStep which will run the GPU's for one step and return the results in "representedOutputValues".
   * 3. Put the data from "representedOutputValues" into the appropriate origins.
   *
   * @author Eric Crawford
   */
  public void step(float startTime, float endTime){
   
    myStartTime = startTime;
    myEndTime = endTime;

   
    if(myGPUEnsembles.length > 0){
   
      try {
       
        int count, i, j;
        float[] inputRow = new float[0];
        Termination[] terminations;
       
        // get the input data from the terminations
        for (i = 0; i < myGPUNetworkArrays.length; i++) {
          terminations = myGPUNetworkArrays[i].getTerminations();
          count = terminations.length;
         
          for (j = 0; j < count; j++) {
            // we only get input for non-GPU terminations
            if (!inputOnGPU[i][j]) {
              inputRow = ((RealOutput) terminations[j].getInput()).getValues();
               
              representedInputValues[i][j] = inputRow;
            }
          }
        }
       
 
        nativeStep(representedInputValues, representedOutputValues, spikeOutput, startTime, endTime);
 
       
        // Put data computed by GPU in the origins
        Origin[] origins;
        for (i = 0; i < myGPUNetworkArrays.length; i++) {
 
          if(myGPUNetworkArrays[i] instanceof NEFEnsembleImpl)
          {
            origins = ((NEFEnsembleImpl) myGPUNetworkArrays[i]).getDecodedOrigins();
          }else{
            origins = myGPUNetworkArrays[i].getOrigins();
          }
         
          count = origins.length;
 
          for (j = 0; j < count; j++) {
            float[] currentRepOutput = representedOutputValues[i][j];
            if(currentRepOutput != null){
              origins[j].setValues(new RealOutputImpl(
                  currentRepOutput.clone(),
                    Units.UNK, endTime));
            }
          }
        }
       
       
        for(i = 0; i < myGPUEnsembles.length; i++){
            NEFEnsembleImpl currentEnsemble = myGPUEnsembles[i];
           
            currentEnsemble.setTime(endTime);
           
            float[] currentSpikeOutput = spikeOutput[i];
            if (currentSpikeOutput != null) {
                currentEnsemble.setSpikePattern(currentSpikeOutput, endTime);
            }
        }
       
       
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
   
   
  }
 

  public void kill()
  {
    if (myGPUEnsembles.length == 0)
      return;
   
    nativeKill();
  }

  /**
   * Used when there are multiple GPU's running a simulation. Finds a distribution of nodes to GPU's that minimizes
   * communication between GPU's while also ensuring the number of neurons running on each GPU is relatively balanced.
   * Note that this problem (a variant of the min bisection problem) is NP-Complete, so a heuristic is employed.
   *
   * @return an array of integers where the value in the i'th entry denotes the partition number of the i'th node ...
   * in the "nodes" input array
   *
   * @author Eric Crawford
   */
  public static int[] findOptimalNodeAssignments(Node[] nodes, Projection[] projections, int numPartitions){
   
    if(numPartitions < 1)
    {
      return new int[0];
    }else if(numPartitions == 1){
      int[] nodeAssignments = new int[nodes.length];
      Arrays.fill(nodeAssignments, 0);
      return nodeAssignments;
    }
   
    MultiLevelKLNetworkPartitioner networkPartitioner = new MultiLevelKLNetworkPartitioner();
    networkPartitioner.initialize(nodes, projections, numPartitions);
   
    return networkPartitioner.getPartitionsAsIntArray();
  }
 
  /**
   * Finds all nodes in the given array which are supposed to execute on the GPU. Stores
   * those nodes in myGPUNetworkArrays and returns the rest.
   *
   * @author Eric Crawford
   */
  public Node[] takeGPUNodes(Node[] nodes){
    ArrayList<Node> gpuNodeList = new ArrayList<Node>();
    ArrayList<Node> nodeList = new ArrayList<Node>();
   
    for(int i = 0; i < nodes.length; i++){
      Node workingNode = nodes[i];
      boolean NEFEnsembleUseGPU =
        workingNode instanceof NEFEnsembleImpl && ((NEFEnsembleImpl) workingNode).getUseGPU();
     
      boolean NetworkArrayUseGPU =
        workingNode instanceof NetworkArrayImpl &&
        ((NetworkImpl) workingNode).getUseGPU();
   
      if(NEFEnsembleUseGPU || NetworkArrayUseGPU){
        gpuNodeList.add(workingNode);
      }
      else{
        nodeList.add(workingNode);
      }
    }
   
    myGPUNetworkArrays = gpuNodeList.toArray(new Node[0]);
    return nodeList.toArray(new Node[0]);
  }
 
  /**
   * Finds all projections in the given array which are supposed to execute on the GPU. Stores
   * those projections in myGPUProjections and returns the rest. takeGPUNodes should be called before
   * this is called, since the nodes which run on the GPU determine which projections run on the GPU.
   * (ie a projection runs on the GPU only if both its target and source run on the GPU).
   *
   * @author Eric Crawford
   */
  public Projection[] takeGPUProjections(Projection[] projections){
    // Sort out the GPU projections from the CPU projections
    ArrayList<Projection> gpuProjectionsList = new ArrayList<Projection>();
    ArrayList<Projection> projectionList = new ArrayList<Projection>();
   
    List<Node> GPUNetworkArrayList = Arrays.asList(myGPUNetworkArrays);
   
    for(int i = 0; i < projections.length; i++)
    {
      Node originNode = projections[i].getOrigin().getNode();
      Node terminationNode = projections[i].getTermination().getNode();

      boolean originNodeOnGPU = GPUNetworkArrayList.contains(originNode);
      boolean terminationNodeOnGPU = GPUNetworkArrayList.contains(terminationNode);
     
      if(originNodeOnGPU && terminationNodeOnGPU)
      {
        gpuProjectionsList.add(projections[i]);
      }
      else
      {
        projectionList.add(projections[i]);
      }
    }
   
    myGPUProjections = gpuProjectionsList.toArray(new Projection[0]);
    nonGPUProjections = projectionList.toArray(new Projection[0]);
    return nonGPUProjections;
   
  }

  /**
   * Used to hold data about each network array to pass to native code. Allows
   * the fields to be set by name and returned as an array which is the form
   * the native code expects the data to be in.
   *
   * @author Eric Crawford
   */
  private class NetworkArrayData {
    int numEntries = 7;
   
    public int indexOfFirstNode;
    public int endIndex;
    public int numTerminations;
    public int totalInputSize;
    public int numOrigins;
    public int totalOutputSize;
    public int numNeurons;
   
    public void reset(){
      indexOfFirstNode = 0;
      endIndex = 0;
      numTerminations = 0;
      totalInputSize = 0;
      numOrigins = 0;
      totalOutputSize = 0;
      numNeurons = 0;
    }
   
    public int[] getAsArray() {
      int[] array = new int[numEntries];

      int i = 0;
      array[i++] = indexOfFirstNode;
      array[i++] = endIndex;
      array[i++] = numTerminations;
      array[i++] = totalInputSize;
      array[i++] = numOrigins;
      array[i++] = totalOutputSize;
      array[i++] = numNeurons;
     
      return array;
    }
     
  }

  /**
   * Used to hold data about each ensemble to pass to native code.. Allows
   * the fields to be set by name, but returned as an array which is the form
   * the native code expects the data to be in.
   *
   * @author Eric Crawford
   */
  private class EnsembleData {
    int numEntries = 10;

    public int dimension;
    public int numNeurons;
    public int numOrigins;

    public int totalInputSize;
    public int totalOutputSize;

    public int maxTransformDimension;
    public int maxDecoderDimension;

    public int numDecodedTerminations;
    public int numNonDecodedTerminations;
   
    public int nonDecodedTransformSize;
   

    public void reset() {
      dimension = 0;
      numNeurons = 0;
      numOrigins = 0;

      totalInputSize = 0;
      totalOutputSize = 0;

      maxTransformDimension = 0;
      maxDecoderDimension = 0;
     
      numDecodedTerminations = 0;
      numNonDecodedTerminations = 0;
      nonDecodedTransformSize = 0;
     
    }

    public int[] getAsArray() {
      int[] array = new int[numEntries];

      int i = 0;
      array[i++] = dimension;
      array[i++] = numNeurons;
      array[i++] = numOrigins;

      array[i++] = totalInputSize;
      array[i++] = totalOutputSize;

      array[i++] = maxTransformDimension;
      array[i++] = maxDecoderDimension;
     
      array[i++] = numDecodedTerminations;
      array[i++] = numNonDecodedTerminations;
     
      array[i++] = nonDecodedTransformSize;
     
      return array;
    }
  }
}
TOP

Related Classes of ca.nengo.util.impl.NEFGPUInterface$NetworkArrayData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.