 
 (defprotocol PNeuralTrainingOptional
   "Some layers will want to do things before the forward pass like update random number buffers.
-This allows things like dropout to play well with gradient checking in that prepare-forward can
-be called once but forward can be called multiple times (normally 1 + 2 * n-params)."
+  This allows things like dropout to play well with gradient checking in that prepare-forward can
+  be called once but forward can be called multiple times (normally 1 + 2 * n-params)."
   (prepare-forward [this]))
 
 

  "Protocol for a generic module. All cortex.nn modules must implement this."
  (calc [m input]
    "Performs module calculation, returning an updated module that includes the output and
     any intermediate states computed.")
  (output [m]
    "Returns the calculated output of a module"))


  "Protocol for modules that can be trained input / output pairs."
  (train [this input output]
    "Trains the module to produce the given input / output. Accumulates gradients as necessary.
  Intended for use with update-parameters after completion of a (mini-)batch."))

(defprotocol PGradientOptimiser
  "A gradient optimiser is an abstraction for objects that update parameters based on gradient observations.
  Gradient optimisers typically contain relating to previous observations, momentum etc."
  (compute-parameters
    [optimiser gradient parameters]
    "Computes updated parameters using the given average gradient. Returns the updated gradient optimiser.
  Users can then call `parameters` on this object to get the updated parameters"))

(defprotocol PLossFunction
  "A function that calculates loss of a vector output vs. a target value"
  (loss [this v target]
    "Computes the loss for a value v against a target")
  (loss-gradient [this v target]
    "Computes the gradient of the loss with respect to v"))

(defprotocol PSerialize
  "Default implementation simply calls into {} and adds type.  An override
  is necessary if your class has complex object members instead of simple keys.
  The map must have a key named :record-type that is the fully namespaced
  qualified record class name (.getName (type item)).  The system will look
  for a function map->TypeName in order to create an empty object."
  (->map [this])
  (map-> [this map-data]))

