package org.nd4j.linalg.lossfunctions;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apache.commons.math3.util.Pair;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.lossfunctions.impl.*;

import java.io.Serializable;

/**
 * Interface for loss functions
 */
@JsonTypeInfo(use= JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes(value={
        @JsonSubTypes.Type(value = LossBinaryXENT.class, name = "BinaryXENT"),
        @JsonSubTypes.Type(value = LossHinge.class, name = "Hinge"),
        @JsonSubTypes.Type(value = LossKLD.class, name = "KLD"),
        @JsonSubTypes.Type(value = LossMAE.class, name = "MAE"),
        @JsonSubTypes.Type(value = LossMAPE.class, name = "MAPE"),
        @JsonSubTypes.Type(value = LossMCXENT.class, name = "MCXENT"),
        @JsonSubTypes.Type(value = LossMSE.class, name = "MSE"),
        @JsonSubTypes.Type(value = LossMSLE.class, name = "MSLE")
})
public interface ILossFunction extends Serializable {

    /**
     * Compute the score (loss function value) for the given inputs.
     *
     * @param labels       Label/expected preOutput
     * @param preOutput    Output of the model (neural network)
     * @param activationFn Activation function that should be applied to preOutput
     * @param mask         Mask array; may be null
     * @param average      Whether the score should be averaged (divided by number of rows in labels/preOutput) or not   @return Loss function value
     */
    double computeScore(INDArray labels, INDArray preOutput, String activationFn, INDArray mask, boolean average);

    /**
     * Compute the score (loss function value) for each example individually.
     * For input [numExamples,nOut] returns scores as a column vector: [numExamples,1]
     *
     * @param labels       Labels/expected output
     * @param preOutput    Output of the model (neural network)
     * @param activationFn Activation function that should be applied to preOutput
     * @param mask         @return Loss function value for each example; column vector
     */
    INDArray computeScoreArray(INDArray labels, INDArray preOutput, String activationFn, INDArray mask);

    /**
     * Compute the gradient of the loss function with respect to the inputs: dL/dOutput
     *
     * @param labels       Label/expected output
     * @param preOutput    Output of the model (neural network), before the activation function is applied
     * @param activationFn Activation function that should be applied to preOutput
     * @param mask         Mask array; may be null
     * @return Gradient dL/dPreOut
     */
    INDArray computeGradient(INDArray labels, INDArray preOutput, String activationFn, INDArray mask);

    /**
     * Compute both the score (loss function value) and gradient. This is equivalent to calling {@link #computeScore(INDArray, INDArray, String, INDArray, boolean)}
     * and {@link #computeGradient(INDArray, INDArray, String, INDArray)} individually
     *
     * @param labels       Label/expected output
     * @param preOutput    Output of the model (neural network)
     * @param activationFn Activation function that should be applied to preOutput
     * @param mask         Mask array; may be null
     * @param average      Whether the score should be averaged (divided by number of rows in labels/output) or not
     * @return The score (loss function value) and gradient
     */
    //TODO: do we want to use the apache commons pair here?
    Pair<Double, INDArray> computeGradientAndScore(INDArray labels, INDArray preOutput, String activationFn, INDArray mask, boolean average);

}

@@ -520,32 +520,121 @@
  %22BinaryXENT%22),%0A
+        @JsonSubTypes.Type(value = LossCosineProximity.class, name = %22CosineProximity%22),%0A
         @JsonSub
@@ -1084,16 +1084,273 @@
  %22MSLE%22)
+,%0A        @JsonSubTypes.Type(value = LossNegativeLogLikelihood.class, name = %22NegativeLogLikelihood%22),%0A        @JsonSubTypes.Type(value = LossPoisson.class, name = %22Poisson%22),%0A        @JsonSubTypes.Type(value = LossSquaredHinge.class, name = %22SquaredHinge%22)
 %0A%7D)%0Apubl

Add remaining loss function json subtype annotations