<commit_before>// Copyright 2016 <NAME>
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.dianahep

import scala.language.existentials

import org.dianahep.histogrammar.json._
import org.dianahep.histogrammar.util._

package histogrammar {
  //////////////////////////////////////////////////////////////// CentrallyBin/CentrallyBinned/CentrallyBinning

  /** Split a quantity into bins defined by a set of bin centers, filling only one datum per bin with no overflows or underflows.
    * 
    * Factory produces mutable [[org.dianahep.histogrammar.CentrallyBinning]] and immutable [[org.dianahep.histogrammar.CentrallyBinned]] objects.
    */
  object CentrallyBin extends Factory {
    val name = "CentrallyBin"
    val help = "Split a quantity into bins defined by a set of bin centers, filling only one datum per bin with no overflows or underflows."
    val detailedHelp = """CentrallyBin(bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count())"""

    /** Create an immutable [[org.dianahep.histogrammar.CentrallyBinned]] from arguments (instead of JSON).
      * 
      * @param entries Weighted number of entries (sum of all observed weights).
      * @param bins Centers and values of each bin.
      * @param min Lowest observed value; used to interpret the first bin as a finite PDF (since the first bin technically extends to minus infinity).
      * @param max Highest observed value; used to interpret the last bin as a finite PDF (since the last bin technically extends to plus infinity).
      * @param nanflow Container for data that resulted in `NaN`.
      */
    def ed[V <: Container[V], N <: Container[N]](entries: Double, bins: Iterable[(Double, V)], min: Double, max: Double, nanflow: N) =
      new CentrallyBinned[V, N](entries, immutable.MetricSortedMap(bins.toSeq: _*), min, max, nanflow)

    /** Create an empty, mutable [[org.dianahep.histogrammar.CentrallyBinning]].
      * 
      * @param bins Centers of each bin.
      * @param quantity Numerical function split into fixed but unevenly-spaced bins.
      * @param selection Boolean or non-negative function that cuts or weights entries.
      * @param value New value (note the `=>`: expression is reevaluated every time a new value is needed).
      * @param nanflow Container for data that result in `NaN`.
      */
    def apply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}]
      (bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count()) =
      new CentrallyBinning[DATUM, V, N](quantity, selection, 0.0, value, mutable.MetricSortedMap(bins.toSeq.map((_, value)): _*), java.lang.Double.NaN, java.lang.Double.NaN, nanflow)

    /** Synonym for `apply`. */
    def ing[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}]
      (bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count()) =
      apply(bins, quantity, selection, value, nanflow)

    /** Use [[org.dianahep.histogrammar.CentrallyBinned]] in Scala pattern-matching. */
    def unapply[V <: Container[V], N <: Container[N]](x: CentrallyBinned[V, N]) =
      Some((x.entries, x.bins, x.min, x.max, x.nanflow))
    /** Use [[org.dianahep.histogrammar.CentrallyBinning]] in Scala pattern-matching. */
    def unapply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}](x: CentrallyBinning[DATUM, V, N]) =
      Some((x.entries, x.bins, x.min, x.max, x.nanflow))

    trait Methods[V <: Container[V]] extends CentralBinsDistribution[V] {
      def bins: MetricSortedMap[Double, V]

      /** Set of centers of each bin. */
      def centersSet = bins.iterator.map(_._1).toSet
      /** Iterable over the centers of each bin. */
      def centers = bins.iterator.map(_._1)
      /** Iterable over the containers associated with each bin. */
      def values = bins.iterator.map(_._2)

      /** Return the exact center of the bin that `x` belongs to. */
      def center(x: Double): Double = bins.closest(x).get.key
      /** Return `true` iff `x` is in the nanflow region (equal to `NaN`). */
      def nan(x: Double): Boolean = x.isNaN

      /** Find the lower and upper neighbors of a bin (given by exact bin center). */
      def neighbors(center: Double): (Option[Double], Option[Double]) = {
        if (!bins.contains(center))
          throw new IllegalArgumentException(s"position $center is not the exact center of a bin")
        (bins.closest(Math.nextDown(center), Some((x: Double, v: V) => x < center)).map(_.key), bins.closest(Math.nextUp(center), Some((x: Double, v: V) => x > center)).map(_.key))
      }

      /** Get the low and high edge of a bin (given by exact bin center). */
      def range(center: Double): (Double, Double) = neighbors(center) match {
        case (Some(below), Some(above)) => ((below + center)/2.0, (center + above)/2.0)
        case (None, Some(above)) => (java.lang.Double.NEGATIVE_INFINITY, (center + above)/2.0)
        case (Some(below), None) => ((below + center)/2.0, java.lang.Double.POSITIVE_INFINITY)
        case _ => throw new Exception("can't get here")
      }
    }

    def fromJsonFragment(json: Json): Container[_] = json match {
      case JsonObject(pairs @ _*) if (pairs.keySet == Set("entries", "bins:type", "bins", "min", "max", "nanflow:type", "nanflow")) =>
        val get = pairs.toMap

        val entries = get("entries") match {
          case JsonNumber(x) => x<commit_msg>fix bug (incompatibility) revealed by Travis<commit_after>// Copyright 2016 <NAME>
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.dianahep

import scala.language.existentials

import org.dianahep.histogrammar.json._
import org.dianahep.histogrammar.util._

package histogrammar {
  //////////////////////////////////////////////////////////////// CentrallyBin/CentrallyBinned/CentrallyBinning

  /** Split a quantity into bins defined by a set of bin centers, filling only one datum per bin with no overflows or underflows.
    * 
    * Factory produces mutable [[org.dianahep.histogrammar.CentrallyBinning]] and immutable [[org.dianahep.histogrammar.CentrallyBinned]] objects.
    */
  object CentrallyBin extends Factory {
    val name = "CentrallyBin"
    val help = "Split a quantity into bins defined by a set of bin centers, filling only one datum per bin with no overflows or underflows."
    val detailedHelp = """CentrallyBin(bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count())"""

    /** Create an immutable [[org.dianahep.histogrammar.CentrallyBinned]] from arguments (instead of JSON).
      * 
      * @param entries Weighted number of entries (sum of all observed weights).
      * @param bins Centers and values of each bin.
      * @param min Lowest observed value; used to interpret the first bin as a finite PDF (since the first bin technically extends to minus infinity).
      * @param max Highest observed value; used to interpret the last bin as a finite PDF (since the last bin technically extends to plus infinity).
      * @param nanflow Container for data that resulted in `NaN`.
      */
    def ed[V <: Container[V], N <: Container[N]](entries: Double, bins: Iterable[(Double, V)], min: Double, max: Double, nanflow: N) =
      new CentrallyBinned[V, N](entries, immutable.MetricSortedMap(bins.toSeq: _*), min, max, nanflow)

    /** Create an empty, mutable [[org.dianahep.histogrammar.CentrallyBinning]].
      * 
      * @param bins Centers of each bin.
      * @param quantity Numerical function split into fixed but unevenly-spaced bins.
      * @param selection Boolean or non-negative function that cuts or weights entries.
      * @param value New value (note the `=>`: expression is reevaluated every time a new value is needed).
      * @param nanflow Container for data that result in `NaN`.
      */
    def apply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}]
      (bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count()) =
      new CentrallyBinning[DATUM, V, N](quantity, selection, 0.0, value, mutable.MetricSortedMap(bins.toSeq.map((_, value)): _*), java.lang.Double.NaN, java.lang.Double.NaN, nanflow)

    /** Synonym for `apply`. */
    def ing[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}]
      (bins: Iterable[Double], quantity: NumericalFcn[DATUM], selection: Selection[DATUM] = unweighted[DATUM], value: => V = Count(), nanflow: N = Count()) =
      apply(bins, quantity, selection, value, nanflow)

    /** Use [[org.dianahep.histogrammar.CentrallyBinned]] in Scala pattern-matching. */
    def unapply[V <: Container[V], N <: Container[N]](x: CentrallyBinned[V, N]) =
      Some((x.entries, x.bins, x.min, x.max, x.nanflow))
    /** Use [[org.dianahep.histogrammar.CentrallyBinning]] in Scala pattern-matching. */
    def unapply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}, N <: Container[N] with Aggregation{type Datum >: DATUM}](x: CentrallyBinning[DATUM, V, N]) =
      Some((x.entries, x.bins, x.min, x.max, x.nanflow))

    trait Methods[V <: Container[V]] extends CentralBinsDistribution[V] {
      def bins: MetricSortedMap[Double, V]

      /** Set of centers of each bin. */
      def centersSet = bins.iterator.map(_._1).toSet
      /** Iterable over the centers of each bin. */
      def centers = bins.iterator.map(_._1)
      /** Iterable over the containers associated with each bin. */
      def values = bins.iterator.map(_._2)

      /** Return the exact center of the bin that `x` belongs to. */
      def center(x: Double): Double = bins.closest(x).get.key
      /** Return `true` iff `x` is in the nanflow region (equal to `NaN`). */
      def nan(x: Double): Boolean = x.isNaN

      /** Find the lower and upper neighbors of a bin (given by exact bin center). */
      def neighbors(center: Double): (Option[Double], Option[Double]) = {
        if (!bins.contains(center))
          throw new IllegalArgumentException(s"position $center is not the exact center of a bin")
        (bins.closest(Math.nextAfter(center, java.lang.Double.NEGATIVE_INFINITY), Some((x: Double, v: V) => x < center)).map(_.key), bins.closest(Math.nextAfter(center, java.lang.Double.POSITIVE_INFINITY), Some((x: Double, v: V) => x > center)).map(_.key))
      }

      /** Get the low and high edge of a bin (given by exact bin center). */
      def range(center: Double): (Double, Double) = neighbors(center) match {
        case (Some(below), Some(above)) => ((below + center)/2.0, (center + above)/2.0)
        case (None, Some(above)) => (java.lang.Double.NEGATIVE_INFINITY, (center + above)/2.0)
        case (Some(below), None) => ((below + center)/2.0, java.lang.Double.POSITIVE_INFINITY)
        case _ => throw new Exception("can't get here")
      }
    }

    def fromJsonFragment(json: Json): Container[_] = json match {
      case JsonObject(pairs @ _*) if (pairs.keySet == Set("entries", "bins:type", "bins", "min", "max", "nanflow:type", "nanflow")) =>
        val get = pairs.toMap

        val entries = get("entries") match {
          case JsonNumber(x) => x
{'fraction_non_alphanumeric': 0.13860297006364422, 'fraction_numerical': 0.003300070715801053, 'mean_word_length': 3.367879203843514, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '681316', 'n_tokens_mistral': 3958, 'n_tokens_neox': 3753, 'n_words': 1296}