text: #include <blitzml/smooth_loss/smoothed_hinge_loss.h>
  #include <blitzml/base/math_util.h>
  #include <math.h>
  
  namespace BlitzML {
  
  value_t SmoothedHingeLoss::compute_loss(value_t a_dot_omega, value_t label) const {
    value_t one_minus_label_times_aomega = 1 - label * a_dot_omega;
    if (one_minus_label_times_aomega <= 0.) {
      return 0;
    } else if (one_minus_label_times_aomega <= 1.) {
      return 0.5 * sq(one_minus_label_times_aomega);
    }
    return one_minus_label_times_aomega - 0.5;
  }
  
  
  value_t SmoothedHingeLoss::compute_conjugate(value_t dual_variable,
                                          value_t label) const {
    if (label == 0.) return -0.5;
    value_t one_plus_ratio = 1 + dual_variable / label;
    return (sq(one_plus_ratio) - 1) / 2;
  }
  
  
  value_t SmoothedHingeLoss::compute_deriative(value_t a_dot_omega,
                                          value_t label) const {
    value_t one_minus_label_times_aomega = 1 - label * a_dot_omega;
    if (one_minus_label_times_aomega <= 0.) {
      return 0;
    } else if (one_minus_label_times_aomega <= 1.) {
      return -label * one_minus_label_times_aomega;
    }
    return -label;
  }
  
  
  value_t SmoothedHingeLoss::compute_2nd_derivative(value_t a_dot_omega,
                                               value_t label) const {
    value_t one_minus_label_times_aomega = 1 - label * a_dot_omega;
    if (one_minus_label_times_aomega <= 0.) {
      return MIN_SMOOTH_LOSS_2ND_DERIVATIVE;
    } else if (one_minus_label_times_aomega <= 1.) {
      return sq(label);
    } else {
      return MIN_SMOOTH_LOSS_2ND_DERIVATIVE;
    }
  }
  
  
  value_t SmoothedHingeLoss::lipschitz_constant() const {
    return 1;
  }
  
  } // namespace BlitzML
  
  
  