"
181 | override def equals(that: Any) = that match {
182 | case that: Counting => this.entries === that.entries && this.transform == that.transform
183 | case _ => false
184 | }
185 | override def hashCode() = (entries, transform).hashCode
186 | }
187 | }
188 |
189 |
190 |
191 |
192 | // Note on statistics:
193 |
194 | // Could follow http://statpages.info/confint.html to provide exact Clopper-Pearson bounds for Poisson (Count) and Binomial (Fraction) confidence levels.
195 |
196 | // Inefficient calculation (JavaScript) that assumes the number of entries is an integer (and scales with it!):
197 |
198 | // var vTL=2.5; var vTU=2.5; var vCL=95
199 |
200 | // function CalcCL(form) {
201 | // vTL = eval(form.TL.value)
202 | // vTU = eval(form.TU.value)
203 | // vCL = 100-(vTL+vTU)
204 | // form.CL.value = ''+vCL
205 | // }
206 |
207 | // function CalcTails(form) {
208 | // vCL = eval(form.CL.value)
209 | // vTU = (100-vCL)/2
210 | // vTL = vTU
211 | // form.TL.value = ''+vTL
212 | // form.TU.value = ''+vTU
213 | // }
214 |
215 | // function CalcBin(form) {
216 | // var vx = eval(form.x.value)
217 | // var vN = eval(form.N.value)
218 | // var vP = vx/vN
219 | // form.P.value = Fmt(vP)
220 | // if(vx==0) {
221 | // form.DL.value = "0.0000"
222 | // }
223 | // else {
224 | // var v=vP/2;
225 | // vsL=0;
226 | // vsH=vP;
227 | // var p=vTL/100;
228 | // while ((vsH-vsL)>1e-5) {
229 | // if(BinP(vN,v,vx,vN)>p) {
230 | // vsH=v;
231 | // v=(vsL+v)/2
232 | // }
233 | // else {
234 | // vsL=v;
235 | // v=(v+vsH)/2
236 | // }
237 | // }
238 | // form.DL.value = Fmt(v)
239 | // }
240 | // if(vx==vN) {
241 | // form.DU.value = "1.0000"
242 | // }
243 | // else {
244 | // var v=(1+vP)/2;
245 | // vsL=vP;
246 | // vsH=1;
247 | // var p=vTU/100
248 | // while ((vsH-vsL)>1e-5) {
249 | // if (BinP(vN,v,0,vx)=x1 & k<=x2) {
271 | // s=s+v
272 | // }
273 | // if (tot>1e30) {
274 | // s=s/1e30;
275 | // tot=tot/1e30;
276 | // v=v/1e30
277 | // }
278 | // k=k+1;
279 | // v=v*q*(N+1-k)/k
280 | // }
281 | // return s/tot
282 | // }
283 |
284 | // function CalcPois(form) {
285 | // var vZ = eval(form.Z.value)
286 | // if(vZ==0) {
287 | // form.QL.value = "0.0000"
288 | // }
289 | // else {
290 | // var v=0.5;
291 | // var dv=0.5;
292 | // var p=vTL/100
293 | // while (dv>1e-7) {
294 | // dv=dv/2;
295 | // if (PoisP((1+vZ)*v/(1-v),vZ,1e10)>p) {
296 | // v=v-dv
297 | // }
298 | // else {
299 | // v=v+dv
300 | // }
301 | // }
302 | // form.QL.value = Fmt((1+vZ)*v/(1-v))
303 | // }
304 | // if(vTU==0) {
305 | // form.QU.value = "Infinity"
306 | // }
307 | // else {
308 | // var v=0.5;
309 | // var dv=0.5;
310 | // var p=vTU/100
311 | // while (dv>1e-7) {
312 | // dv=dv/2;
313 | // if (PoisP((1+vZ)*v/(1-v),0,vZ)
(tot*1e-10)) {
327 | // tot=tot+q
328 | // if(k>=x1 & k<=x2) {
329 | // s=s+q
330 | // }
331 | // if (tot>1e30) {
332 | // s=s/1e30;
333 | // tot=tot/1e30;
334 | // q=q/1e30
335 | // }
336 | // k=k+1;
337 | // q=q*Z/k
338 | // }
339 | // return s/tot
340 | // }
341 |
342 | // function Fmt(x) {
343 | // var v
344 | // if (x>=0) {
345 | // v=''+(x+0.00005)
346 | // }
347 | // else {
348 | // v=''+(x-0.00005)
349 | // }
350 | // return v.substring(0,v.indexOf('.')+5)
351 | // }
352 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/primitives/deviate.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep
16 |
17 | import scala.language.existentials
18 |
19 | import org.dianahep.histogrammar.json._
20 | import org.dianahep.histogrammar.util._
21 |
22 | package histogrammar {
23 | //////////////////////////////////////////////////////////////// Deviate/Deviated/Deviating
24 |
25 | /** Accumulate the weighted mean and weighted variance of a given quantity.
26 | *
27 | * The variance is computed around the mean, not zero.
28 | *
29 | * Uses the numerically stable weighted mean and weighted variance algorithms described in Tony Finch, [[http://www-uxsup.csx.cam.ac.uk/~fanf2/hermes/doc/antiforgery/stats.pdf "Incremental calculation of weighted mean and variance"]] ''Univeristy of Cambridge Computing Service, 2009''.
30 | *
31 | * Factory produces mutable [[org.dianahep.histogrammar.Deviating]] and immutable [[org.dianahep.histogrammar.Deviated]] objects.
32 | */
33 | object Deviate extends Factory {
34 | val name = "Deviate"
35 | val help = "Accumulate the weighted mean and weighted variance of a given quantity."
36 | val detailedHelp = """The variance is computed around the mean, not zero.
37 |
38 | Uses the numerically stable weighted mean and weighted variance algorithms described in Tony Finch, [[http://www-uxsup.csx.cam.ac.uk/~fanf2/hermes/doc/antiforgery/stats.pdf "Incremental calculation of weighted mean and variance"]] ''Univeristy of Cambridge Computing Service, 2009''."""
39 |
40 | /** Create an immutable [[org.dianahep.histogrammar.Deviated]] from arguments (instead of JSON).
41 | *
42 | * @param entries Weighted number of entries (sum of all observed weights).
43 | * @param mean Weighted mean of the quantity.
44 | * @param variance Weighted variance of the quantity.
45 | */
46 | def ed(entries: Double, mean: Double, variance: Double) = new Deviated(entries, None, mean, variance)
47 |
48 | /** Create an empty, mutable [[org.dianahep.histogrammar.Deviating]].
49 | *
50 | * @param quantity Numerical function to track.
51 | */
52 | def apply[DATUM](quantity: UserFcn[DATUM, Double]) = new Deviating(quantity, 0.0, java.lang.Double.NaN, java.lang.Double.NaN)
53 |
54 | /** Synonym for `apply`. */
55 | def ing[DATUM](quantity: UserFcn[DATUM, Double]) = apply(quantity)
56 |
57 | /** Use [[org.dianahep.histogrammar.Deviated]] in Scala pattern-matching. */
58 | def unapply(x: Deviated) = Some(x.variance)
59 | /** Use [[org.dianahep.histogrammar.Deviating]] in Scala pattern-matching. */
60 | def unapply[DATUM](x: Deviating[DATUM]) = Some(x.variance)
61 |
62 | import KeySetComparisons._
63 | def fromJsonFragment(json: Json, nameFromParent: Option[String]): Container[_] with NoAggregation = json match {
64 | case JsonObject(pairs @ _*) if (pairs.keySet has Set("entries", "mean", "variance").maybe("name")) =>
65 | val get = pairs.toMap
66 |
67 | val entries = get("entries") match {
68 | case JsonNumber(x) => x
69 | case x => throw new JsonFormatException(x, name + ".entries")
70 | }
71 |
72 | val quantityName = get.getOrElse("name", JsonNull) match {
73 | case JsonString(x) => Some(x)
74 | case JsonNull => None
75 | case x => throw new JsonFormatException(x, name + ".name")
76 | }
77 |
78 | val mean = get("mean") match {
79 | case JsonNumber(x) => x
80 | case x => throw new JsonFormatException(x, name + ".mean")
81 | }
82 |
83 | val variance = get("variance") match {
84 | case JsonNumber(x) => x
85 | case x => throw new JsonFormatException(x, name + ".variance")
86 | }
87 |
88 | new Deviated(entries, (nameFromParent ++ quantityName).lastOption, mean, variance)
89 |
90 | case _ => throw new JsonFormatException(json, name)
91 | }
92 |
93 | private[histogrammar] def plus(ca: Double, mua: Double, sa: Double, cb: Double, mub: Double, sb: Double) =
94 | if (ca == 0.0)
95 | (cb, mub, sb / cb)
96 | else if (cb == 0.0)
97 | (ca, mua, sa / ca)
98 | else {
99 | val muab = (ca*mua + cb*mub)/(ca + cb)
100 | val sab = sa + sb + ca*mua*mua + cb*mub*mub - 2.0*muab*(ca*mua + cb*mub) + muab*muab*(ca + cb)
101 | (ca + cb, muab, sab / (ca + cb))
102 | }
103 | }
104 |
105 | /** An accumulated weighted variance (and mean) of a given quantity.
106 | *
107 | * Use the factory [[org.dianahep.histogrammar.Deviate]] to construct an instance.
108 | *
109 | * @param entries Weighted number of entries (sum of all observed weights).
110 | * @param quantityName Optional name given to the quantity function, passed for bookkeeping.
111 | * @param mean Weighted mean of the quantity.
112 | * @param variance Weighted variance of the quantity.
113 | *
114 | * The implementation of this container uses a numerically stable variance as described by Tony Finch in [[http://www-uxsup.csx.cam.ac.uk/~fanf2/hermes/doc/antiforgery/stats.pdf "Incremental calculation of weighted mean and variance,"]] ''Univeristy of Cambridge Computing Service,'' 2009.
115 | */
116 | class Deviated private[histogrammar](val entries: Double, val quantityName: Option[String], val mean: Double, val variance: Double) extends Container[Deviated] with NoAggregation with QuantityName {
117 | type Type = Deviated
118 | type EdType = Deviated
119 | def factory = Deviate
120 |
121 | if (entries < 0.0)
122 | throw new ContainerException(s"entries ($entries) cannot be negative")
123 |
124 | def zero = new Deviated(0.0, quantityName, java.lang.Double.NaN, java.lang.Double.NaN)
125 | def +(that: Deviated) =
126 | if (this.quantityName != that.quantityName)
127 | throw new ContainerException(s"cannot add ${getClass.getName} because quantityName differs (${this.quantityName} vs ${that.quantityName})")
128 | else {
129 | val (newentries, newmean, newvariance) = Deviate.plus(this.entries, this.mean, this.variance * this.entries,
130 | that.entries, that.mean, that.variance * that.entries)
131 | new Deviated(newentries, this.quantityName, newmean, newvariance)
132 | }
133 | def *(factor: Double) =
134 | if (factor.isNaN || factor <= 0.0)
135 | zero
136 | else
137 | new Deviated(factor * entries, quantityName, mean, variance)
138 |
139 | def children = Nil
140 |
141 | def toJsonFragment(suppressName: Boolean) = JsonObject(
142 | "entries" -> JsonFloat(entries),
143 | "mean" -> JsonFloat(mean),
144 | "variance" -> JsonFloat(variance)).
145 | maybe(JsonString("name") -> (if (suppressName) None else quantityName.map(JsonString(_))))
146 |
147 | override def toString() = s""
148 | override def equals(that: Any) = that match {
149 | case that: Deviated => this.entries === that.entries && this.quantityName == that.quantityName && this.mean === that.mean && this.variance === that.variance
150 | case _ => false
151 | }
152 | override def hashCode() = (entries, quantityName, mean, variance).hashCode
153 | }
154 |
155 | /** Accumulating a weighted variance (and mean) of a given quantity.
156 | *
157 | * Use the factory [[org.dianahep.histogrammar.Deviate]] to construct an instance.
158 | *
159 | * @param quantity Numerical function to track.
160 | * @param entries Weighted number of entries (sum of all observed weights).
161 | * @param mean Weighted mean of the quantity.
162 | * @param _variance Weighted variance of the quantity.
163 | *
164 | * The implementation of this container uses a numerically stable variance as described by Tony Finch in [[http://www-uxsup.csx.cam.ac.uk/~fanf2/hermes/doc/antiforgery/stats.pdf "Incremental calculation of weighted mean and variance,"]] ''Univeristy of Cambridge Computing Service,'' 2009.
165 | */
166 | class Deviating[DATUM] private[histogrammar](val quantity: UserFcn[DATUM, Double], var entries: Double, var mean: Double, _variance: Double) extends Container[Deviating[DATUM]] with AggregationOnData with NumericalQuantity[DATUM] {
167 | type Type = Deviating[DATUM]
168 | type EdType = Deviated
169 | type Datum = DATUM
170 | def factory = Deviate
171 |
172 | if (entries < 0.0)
173 | throw new ContainerException(s"entries ($entries) cannot be negative")
174 |
175 | private var varianceTimesEntries = entries * _variance
176 |
177 | /** weighted variance of the quantity */
178 | def variance =
179 | if (entries == 0.0)
180 | _variance
181 | else
182 | varianceTimesEntries / entries
183 |
184 | def variance_=(_variance: Double): Unit = {
185 | varianceTimesEntries = entries * _variance
186 | }
187 |
188 | def zero = new Deviating[DATUM](quantity, 0.0, java.lang.Double.NaN, java.lang.Double.NaN)
189 | def +(that: Deviating[DATUM]) =
190 | if (this.quantity.name != that.quantity.name)
191 | throw new ContainerException(s"cannot add ${getClass.getName} because quantity name differs (${this.quantity.name} vs ${that.quantity.name})")
192 | else {
193 | val (newentries, newmean, newvariance) = Deviate.plus(this.entries, this.mean, this.variance * this.entries,
194 | that.entries, that.mean, that.variance * that.entries)
195 | new Deviating[DATUM](this.quantity, newentries, newmean, newvariance)
196 | }
197 | def *(factor: Double) =
198 | if (factor.isNaN || factor <= 0.0)
199 | zero
200 | else
201 | new Deviating[DATUM](quantity, factor * entries, mean, variance)
202 |
203 | def fill[SUB <: Datum](datum: SUB, weight: Double = 1.0): Unit = {
204 | checkForCrossReferences()
205 | if (weight > 0.0) {
206 | val q = quantity(datum)
207 |
208 | // no possibility of exception from here on out (for rollback)
209 | if (entries == 0.0) {
210 | mean = q
211 | varianceTimesEntries = 0.0
212 | }
213 | entries += weight
214 |
215 | if (mean.isNaN || q.isNaN) {
216 | mean = java.lang.Double.NaN
217 | varianceTimesEntries = java.lang.Double.NaN
218 | }
219 |
220 | else if (mean.isInfinite || q.isInfinite) {
221 | if (mean.isInfinite && q.isInfinite && mean * q < 0.0)
222 | mean = java.lang.Double.NaN
223 | else if (q.isInfinite)
224 | mean = q
225 | else
226 | { }
227 | if (entries.isInfinite || entries.isNaN)
228 | mean = java.lang.Double.NaN
229 |
230 | varianceTimesEntries = java.lang.Double.NaN
231 | }
232 |
233 | else {
234 | val delta = q - mean
235 | val shift = delta * weight / entries
236 | mean += shift
237 | varianceTimesEntries += weight * delta * (q - mean) // old delta times new delta
238 | }
239 | }
240 | }
241 |
242 | def children = Nil
243 |
244 | def toJsonFragment(suppressName: Boolean) = JsonObject(
245 | "entries" -> JsonFloat(entries),
246 | "mean" -> JsonFloat(mean),
247 | "variance" -> JsonFloat(variance)).
248 | maybe(JsonString("name") -> (if (suppressName) None else quantity.name.map(JsonString(_))))
249 |
250 | override def toString() = s""
251 | override def equals(that: Any) = that match {
252 | case that: Deviating[DATUM] => this.quantity == that.quantity && this.entries === that.entries && this.mean === that.mean && this.variance === that.variance
253 | case _ => false
254 | }
255 | override def hashCode() = (quantity, entries, mean, variance).hashCode
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/primitives/minmax.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep
16 |
17 | import scala.language.existentials
18 |
19 | import org.dianahep.histogrammar.json._
20 | import org.dianahep.histogrammar.util._
21 |
22 | package histogrammar {
23 | //////////////////////////////////////////////////////////////// Minimize/Minimized/Minimizing
24 |
25 | /** Find the minimum value of a given quantity. If no data are observed, the result is NaN.
26 | *
27 | * Factory produces mutable [[org.dianahep.histogrammar.Minimizing]] and immutable [[org.dianahep.histogrammar.Minimized]] objects.
28 | */
29 | object Minimize extends Factory {
30 | val name = "Minimize"
31 | val help = "Find the minimum value of a given quantity. If no data are observed, the result is NaN."
32 | val detailedHelp = """"""
33 |
34 | /** Create an immutable [[org.dianahep.histogrammar.Minimized]] from arguments (instead of JSON).
35 | *
36 | * @param entries Weighted number of entries (sum of all observed weights).
37 | * @param min Lowest observed value.
38 | */
39 | def ed(entries: Double, min: Double) = new Minimized(entries, None, min)
40 |
41 | /** Create an immutable [[org.dianahep.histogrammar.Minimizing]].
42 | *
43 | * @param quantity Numerical function to track.
44 | */
45 | def apply[DATUM](quantity: UserFcn[DATUM, Double]) = new Minimizing(quantity, 0.0, java.lang.Double.NaN)
46 |
47 | /** Synonym for `apply`. */
48 | def ing[DATUM](quantity: UserFcn[DATUM, Double]) = apply(quantity)
49 |
50 | /** Use [[org.dianahep.histogrammar.Minimized]] in Scala pattern-matching. */
51 | def unapply(x: Minimized) = Some(x.min)
52 | /** Use [[org.dianahep.histogrammar.Minimizing]] in Scala pattern-matching. */
53 | def unapply[DATUM](x: Minimizing[DATUM]) = Some(x.min)
54 |
55 | import KeySetComparisons._
56 | def fromJsonFragment(json: Json, nameFromParent: Option[String]): Container[_] with NoAggregation = json match {
57 | case JsonObject(pairs @ _*) if (pairs.keySet has Set("entries", "min").maybe("name")) =>
58 | val get = pairs.toMap
59 |
60 | val entries = get("entries") match {
61 | case JsonNumber(x) => x
62 | case x => throw new JsonFormatException(x, name + ".entries")
63 | }
64 |
65 | val quantityName = get.getOrElse("name", JsonNull) match {
66 | case JsonString(x) => Some(x)
67 | case JsonNull => None
68 | case x => throw new JsonFormatException(x, name + ".name")
69 | }
70 |
71 | get("min") match {
72 | case JsonNumber(x) => new Minimized(entries, (nameFromParent ++ quantityName).lastOption, x)
73 | case x => throw new JsonFormatException(x, name)
74 | }
75 |
76 | case _ => throw new JsonFormatException(json, name)
77 | }
78 |
79 | private[histogrammar] def plus(one: Double, two: Double) =
80 | if (one.isNaN)
81 | two
82 | else if (two.isNaN)
83 | one
84 | else if (one < two)
85 | one
86 | else
87 | two
88 | }
89 |
90 | /** An accumulated minimum of a given quantity. If no data are observed, the result is `NaN`.
91 | *
92 | * Use the factory [[org.dianahep.histogrammar.Minimize]] to construct an instance.
93 | *
94 | * @param entries Weighted number of entries (sum of all observed weights).
95 | * @param quantityName Optional name given to the quantity function, passed for bookkeeping.
96 | * @param min Lowest observed value.
97 | */
98 | class Minimized private[histogrammar](val entries: Double, val quantityName: Option[String], val min: Double) extends Container[Minimized] with NoAggregation with QuantityName {
99 | type Type = Minimized
100 | type EdType = Minimized
101 | def factory = Minimize
102 |
103 | if (entries < 0.0)
104 | throw new ContainerException(s"entries ($entries) cannot be negative")
105 |
106 | def zero = new Minimized(0.0, quantityName, java.lang.Double.NaN)
107 | def +(that: Minimized) =
108 | if (this.quantityName != that.quantityName)
109 | throw new ContainerException(s"cannot add ${getClass.getName} because quantityName differs (${this.quantityName} vs ${that.quantityName})")
110 | else
111 | new Minimized(this.entries + that.entries, quantityName, Minimize.plus(this.min, that.min))
112 | def *(factor: Double) =
113 | if (factor.isNaN || factor <= 0.0)
114 | zero
115 | else
116 | new Minimized(factor * entries, quantityName, min)
117 |
118 | def children = Nil
119 |
120 | def toJsonFragment(suppressName: Boolean) = JsonObject(
121 | "entries" -> JsonFloat(entries),
122 | "min" -> JsonFloat(min)).
123 | maybe(JsonString("name") -> (if (suppressName) None else quantityName.map(JsonString(_))))
124 |
125 | override def toString() = s""""""
126 | override def equals(that: Any) = that match {
127 | case that: Minimized => this.entries === that.entries && this.quantityName == that.quantityName && this.min === that.min
128 | case _ => false
129 | }
130 | override def hashCode() = (entries, quantityName, min).hashCode
131 | }
132 |
133 | /** Accumulating the minimum of a given quantity. If no data are observed, the result is `NaN`.
134 | *
135 | * Use the factory [[org.dianahep.histogrammar.Minimize]] to construct an instance.
136 | *
137 | * @param quantity Numerical function to track.
138 | * @param entries Weighted number of entries (sum of all observed weights).
139 | * @param min Lowest observed value.
140 | */
141 | class Minimizing[DATUM] private[histogrammar](val quantity: UserFcn[DATUM, Double], var entries: Double, var min: Double) extends Container[Minimizing[DATUM]] with AggregationOnData with NumericalQuantity[DATUM] {
142 | type Type = Minimizing[DATUM]
143 | type EdType = Minimized
144 | type Datum = DATUM
145 | def factory = Minimize
146 |
147 | def zero = new Minimizing[DATUM](quantity, 0.0, java.lang.Double.NaN)
148 | def +(that: Minimizing[DATUM]) =
149 | if (this.quantity.name != that.quantity.name)
150 | throw new ContainerException(s"cannot add ${getClass.getName} because quantity name differs (${this.quantity.name} vs ${that.quantity.name})")
151 | else
152 | new Minimizing[DATUM](this.quantity, this.entries + that.entries, Minimize.plus(this.min, that.min))
153 | def *(factor: Double) =
154 | if (factor.isNaN || factor <= 0.0)
155 | zero
156 | else
157 | new Minimizing[DATUM](quantity, factor * entries, min)
158 |
159 | def fill[SUB <: Datum](datum: SUB, weight: Double = 1.0): Unit = {
160 | checkForCrossReferences()
161 | if (weight > 0.0) {
162 | val q = quantity(datum)
163 |
164 | // no possibility of exception from here on out (for rollback)
165 | entries += weight
166 | if (min.isNaN || q < min)
167 | min = q
168 | }
169 | }
170 |
171 | def children = Nil
172 |
173 | def toJsonFragment(suppressName: Boolean) = JsonObject(
174 | "entries" -> JsonFloat(entries),
175 | "min" -> JsonFloat(min)).
176 | maybe(JsonString("name") -> (if (suppressName) None else quantity.name.map(JsonString(_))))
177 |
178 | override def toString() = s""""""
179 | override def equals(that: Any) = that match {
180 | case that: Minimizing[DATUM] => this.quantity == that.quantity && this.entries === that.entries && this.min === that.min
181 | case _ => false
182 | }
183 | override def hashCode() = (quantity, entries, min).hashCode
184 | }
185 |
186 | //////////////////////////////////////////////////////////////// Maximize/Maximized/Maximizing
187 |
188 | /** Find the maximum value of a given quantity. If no data are observed, the result is NaN.
189 | *
190 | * Factory produces mutable [[org.dianahep.histogrammar.Maximizing]] and immutable [[org.dianahep.histogrammar.Maximized]] objects.
191 | */
192 | object Maximize extends Factory {
193 | val name = "Maximize"
194 | val help = "Find the maximum value of a given quantity. If no data are observed, the result is NaN."
195 | val detailedHelp = """"""
196 |
197 | /** Create an immutable [[org.dianahep.histogrammar.Maximized]] from arguments (instead of JSON).
198 | *
199 | * @param entries Weighted number of entries (sum of all observed weights).
200 | * @param max Highest observed value.
201 | */
202 | def ed(entries: Double, max: Double) = new Maximized(entries, None, max)
203 |
204 | /** Create an immutable [[org.dianahep.histogrammar.Maximizing]].
205 | *
206 | * @param quantity Numerical function to track.
207 | */
208 | def apply[DATUM](quantity: UserFcn[DATUM, Double]) = new Maximizing(quantity, 0.0, java.lang.Double.NaN)
209 |
210 | /** Synonym for `apply`. */
211 | def ing[DATUM](quantity: UserFcn[DATUM, Double]) = apply(quantity)
212 |
213 | /** Use [[org.dianahep.histogrammar.Maximized]] in Scala pattern-matching. */
214 | def unapply(x: Maximized) = Some(x.max)
215 | /** Use [[org.dianahep.histogrammar.Maximizing]] in Scala pattern-matching. */
216 | def unapply[DATUM](x: Maximizing[DATUM]) = Some(x.max)
217 |
218 | import KeySetComparisons._
219 | def fromJsonFragment(json: Json, nameFromParent: Option[String]): Container[_] with NoAggregation = json match {
220 | case JsonObject(pairs @ _*) if (pairs.keySet has Set("entries", "max").maybe("name")) =>
221 | val get = pairs.toMap
222 |
223 | val entries = get("entries") match {
224 | case JsonNumber(x) => x
225 | case x => throw new JsonFormatException(x, name + ".entries")
226 | }
227 |
228 | val quantityName = get.getOrElse("name", JsonNull) match {
229 | case JsonString(x) => Some(x)
230 | case JsonNull => None
231 | case x => throw new JsonFormatException(x, name + ".name")
232 | }
233 |
234 | get("max") match {
235 | case JsonNumber(x) => new Maximized(entries, (nameFromParent ++ quantityName).lastOption, x)
236 | case x => throw new JsonFormatException(x, name)
237 | }
238 |
239 | case _ => throw new JsonFormatException(json, name)
240 | }
241 |
242 | private[histogrammar] def plus(one: Double, two: Double) =
243 | if (one.isNaN)
244 | two
245 | else if (two.isNaN)
246 | one
247 | else if (one > two)
248 | one
249 | else
250 | two
251 | }
252 |
253 | /** An accumulated maximum of a given quantity. If no data are observed, the result is `NaN`.
254 | *
255 | * Use the factory [[org.dianahep.histogrammar.Maximize]] to construct an instance.
256 | *
257 | * @param entries Weighted number of entries (sum of all observed weights).
258 | * @param quantityName Optional name given to the quantity function, passed for bookkeeping.
259 | * @param max Highest observed value.
260 | */
261 | class Maximized private[histogrammar](val entries: Double, val quantityName: Option[String], val max: Double) extends Container[Maximized] with NoAggregation with QuantityName {
262 | type Type = Maximized
263 | type EdType = Maximized
264 | def factory = Maximize
265 |
266 | def zero = new Maximized(0.0, quantityName, java.lang.Double.NaN)
267 | def +(that: Maximized) =
268 | if (this.quantityName != that.quantityName)
269 | throw new ContainerException(s"cannot add ${getClass.getName} because quantityName differs (${this.quantityName} vs ${that.quantityName})")
270 | else
271 | new Maximized(this.entries + that.entries, this.quantityName, Maximize.plus(this.max, that.max))
272 | def *(factor: Double) =
273 | if (factor.isNaN || factor <= 0.0)
274 | zero
275 | else
276 | new Maximized(factor * entries, quantityName, max)
277 |
278 | def children = Nil
279 |
280 | def toJsonFragment(suppressName: Boolean) = JsonObject(
281 | "entries" -> JsonFloat(entries),
282 | "max" -> JsonFloat(max)).
283 | maybe(JsonString("name") -> (if (suppressName) None else quantityName.map(JsonString(_))))
284 |
285 | override def toString() = s""""""
286 | override def equals(that: Any) = that match {
287 | case that: Maximized => this.entries === that.entries && this.quantityName == that.quantityName && this.max === that.max
288 | case _ => false
289 | }
290 | override def hashCode() = (entries, quantityName, max).hashCode
291 | }
292 |
293 | /** Accumulating the maximum of a given quantity. If no data are observed, the result is `NaN`.
294 | *
295 | * Use the factory [[org.dianahep.histogrammar.Maximize]] to construct an instance.
296 | *
297 | * @param quantity Numerical function to track.
298 | * @param entries Weighted number of entries (sum of all observed weights).
299 | * @param max Highest observed value.
300 | */
301 | class Maximizing[DATUM] private[histogrammar](val quantity: UserFcn[DATUM, Double], var entries: Double, var max: Double) extends Container[Maximizing[DATUM]] with AggregationOnData with NumericalQuantity[DATUM] {
302 | type Type = Maximizing[DATUM]
303 | type EdType = Maximized
304 | type Datum = DATUM
305 | def factory = Maximize
306 |
307 | def zero = new Maximizing[DATUM](quantity, 0.0, java.lang.Double.NaN)
308 | def +(that: Maximizing[DATUM]) =
309 | if (this.quantity.name != that.quantity.name)
310 | throw new ContainerException(s"cannot add ${getClass.getName} because quantity name differs (${this.quantity.name} vs ${that.quantity.name})")
311 | else
312 | new Maximizing[DATUM](this.quantity, this.entries + that.entries, Maximize.plus(this.max, that.max))
313 | def *(factor: Double) =
314 | if (factor.isNaN || factor <= 0.0)
315 | zero
316 | else
317 | new Maximizing[DATUM](quantity, factor * entries, max)
318 |
319 | def fill[SUB <: Datum](datum: SUB, weight: Double = 1.0): Unit = {
320 | checkForCrossReferences()
321 | if (weight > 0.0) {
322 | val q = quantity(datum)
323 |
324 | // no possibility of exception from here on out (for rollback)
325 | entries += weight
326 | if (max.isNaN || q > max)
327 | max = q
328 | }
329 | }
330 |
331 | def children = Nil
332 |
333 | def toJsonFragment(suppressName: Boolean) = JsonObject(
334 | "entries" -> JsonFloat(entries),
335 | "max" -> JsonFloat(max)).
336 | maybe(JsonString("name") -> (if (suppressName) None else quantity.name.map(JsonString(_))))
337 |
338 | override def toString() = s""""""
339 | override def equals(that: Any) = that match {
340 | case that: Maximizing[DATUM] => this.quantity == that.quantity && this.entries === that.entries && this.max === that.max
341 | case _ => false
342 | }
343 | override def hashCode() = (quantity, entries, max).hashCode
344 | }
345 | }
346 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/primitives/select.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep
16 |
17 | import scala.language.existentials
18 |
19 | import org.dianahep.histogrammar.json._
20 | import org.dianahep.histogrammar.util._
21 |
22 | package histogrammar {
23 | //////////////////////////////////////////////////////////////// Select/Selected/Selecting
24 |
25 | /** Filter or weight data according to a given selection.
26 | *
27 | * This primitive is a basic building block, intended to be used in conjunction with anything that needs a user-defined cut. In particular, a standard histogram often has a custom selection, and this can be built by nesting Select -> Bin -> Count.
28 | *
29 | * Select also resembles [[org.dianahep.histogrammar.Fraction]], but without the `denominator`.
30 | *
31 | * The efficiency of a cut in a Select aggregator named `x` is simply `x.cut.entries / x.entries` (because all aggregators have an `entries` member).
32 | *
33 | * Factory produces mutable [[org.dianahep.histogrammar.Selecting]] and immutable [[org.dianahep.histogrammar.Selected]] (sic) objects.
34 | */
35 | object Select extends Factory {
36 | val name = "Select"
37 | val help = "Filter or weight data according to a given selection."
38 | val detailedHelp = """This primitive is a basic building block, intended to be used in conjunction with anything that needs a user-defined cut. In particular, a standard histogram often has a custom selection, and this can be built by nesting Select -> Bin -> Count.
39 |
40 | Select also resembles [[org.dianahep.histogrammar.Fraction]], but without the `denominator`.
41 |
42 | The efficiency of a cut in a Select aggregator named `x` is simply `x.cut.entries / x.entries` (because all aggregators have an `entries` member)."""
43 |
44 | /** Create an immutable [[org.dianahep.histogrammar.Selected]] from arguments (instead of JSON).
45 | *
46 | * @param entries Weighted number of entries (sum of all observed weights without the cut applied).
47 | * @param cut Aggregator that accumulated values that passed the cut.
48 | */
49 | def ed[V <: Container[V] with NoAggregation](entries: Double, cut: V) = new Selected[V](entries, None, cut)
50 |
51 | /** Create an empty, mutable [[org.dianahep.histogrammar.Selecting]].
52 | *
53 | * @param quantity Boolean or non-negative function that cuts or weights entries.
54 | * @param cut Aggregator to accumulate for values that pass the selection (`quantity`).
55 | */
56 | def apply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}](quantity: UserFcn[DATUM, Double], cut: V = Count()) = new Selecting[DATUM, V](0.0, quantity, cut)
57 |
58 | /** Synonym for `apply`. */
59 | def ing[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}](quantity: UserFcn[DATUM, Double], cut: V = Count()) = apply(quantity, cut)
60 |
61 | /** Use [[org.dianahep.histogrammar.Selected]] in Scala pattern-matching. */
62 | def unapply[V <: Container[V] with NoAggregation](x: Selected[V]) = Some(x.cut)
63 | /** Use [[org.dianahep.histogrammar.Selecting]] in Scala pattern-matching. */
64 | def unapply[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}](x: Selecting[DATUM, V]) = Some(x.cut)
65 |
66 | import KeySetComparisons._
67 | def fromJsonFragment(json: Json, nameFromParent: Option[String]): Container[_] with NoAggregation = json match {
68 | case JsonObject(pairs @ _*) if (pairs.keySet has Set("entries", "sub:type", "data").maybe("name")) =>
69 | val get = pairs.toMap
70 |
71 | val entries = get("entries") match {
72 | case JsonNumber(x) => x
73 | case x => throw new JsonFormatException(x, name + ".entries")
74 | }
75 |
76 | val quantityName = get.getOrElse("name", JsonNull) match {
77 | case JsonString(x) => Some(x)
78 | case JsonNull => None
79 | case x => throw new JsonFormatException(x, name + ".name")
80 | }
81 |
82 | val factory = get("sub:type") match {
83 | case JsonString(x) => Factory(x)
84 | case x => throw new JsonFormatException(x, name + ".type")
85 | }
86 |
87 | val cut = factory.fromJsonFragment(get("data"), None)
88 |
89 | new Selected(entries, (nameFromParent ++ quantityName).lastOption, cut.asInstanceOf[C forSome {type C <: Container[C] with NoAggregation}])
90 |
91 | case _ => throw new JsonFormatException(json, name)
92 | }
93 |
94 | trait Methods {
95 | /** Fraction of weights that pass the quantity. */
96 | def fractionPassing: Double
97 | }
98 | }
99 |
100 | /** An accumulated aggregator of data that passed the cut.
101 | *
102 | * @param entries Weighted number of entries (sum of all observed weights without the cut applied).
103 | * @param quantityName Optional name given to the quantity function, passed for bookkeeping.
104 | * @param cut Aggregator that accumulated values that passed the cut.
105 | */
106 | class Selected[V <: Container[V] with NoAggregation] private[histogrammar](val entries: Double, val quantityName: Option[String], val cut: V) extends Container[Selected[V]] with NoAggregation with QuantityName with Select.Methods {
107 | type Type = Selected[V]
108 | type EdType = Selected[V]
109 | def factory = Select
110 |
111 | if (entries < 0.0)
112 | throw new ContainerException(s"entries ($entries) cannot be negative")
113 |
114 | def fractionPassing = cut.entries / entries
115 |
116 | def zero = new Selected[V](0.0, quantityName, cut.zero)
117 | def +(that: Selected[V]) =
118 | if (this.quantityName != that.quantityName)
119 | throw new ContainerException(s"cannot add ${getClass.getName} because quantityName differs (${this.quantityName} vs ${that.quantityName})")
120 | else
121 | new Selected[V](this.entries + that.entries, this.quantityName, this.cut + that.cut)
122 | def *(factor: Double) =
123 | if (factor.isNaN || factor <= 0.0)
124 | zero
125 | else
126 | new Selected[V](factor * entries, quantityName, cut * factor)
127 |
128 | def children = cut :: Nil
129 |
130 | def toJsonFragment(suppressName: Boolean) = JsonObject(
131 | "entries" -> JsonFloat(entries),
132 | "sub:type" -> JsonString(cut.factory.name),
133 | "data" -> cut.toJsonFragment(false)).
134 | maybe(JsonString("name") -> (if (suppressName) None else quantityName.map(JsonString(_))))
135 |
136 | override def toString() = s""""""
137 | override def equals(that: Any) = that match {
138 | case that: Selected[V] => this.entries === that.entries && this.quantityName == that.quantityName && this.cut == that.cut
139 | case _ => false
140 | }
141 | override def hashCode() = (entries, quantityName, cut).hashCode
142 | }
143 |
144 | /** Accumulating an aggregator of data that passes a cut.
145 | *
146 | * @param entries Weighted number of entries (sum of all observed weights without the cut applied).
147 | * @param quantity Boolean or non-negative function that cuts or weights entries.
148 | * @param cut Aggregator to accumulate values that pass the cut.
149 | */
150 | class Selecting[DATUM, V <: Container[V] with Aggregation{type Datum >: DATUM}] private[histogrammar](var entries: Double, val quantity: UserFcn[DATUM, Double], val cut: V) extends Container[Selecting[DATUM, V]] with AggregationOnData with NumericalQuantity[DATUM] with Select.Methods {
151 | type Type = Selecting[DATUM, V]
152 | type EdType = Selected[cut.EdType]
153 | type Datum = DATUM
154 | def factory = Select
155 |
156 | if (entries < 0.0)
157 | throw new ContainerException(s"entries ($entries) cannot be negative")
158 |
159 | def fractionPassing = cut.entries / entries
160 |
161 | def zero = new Selecting[DATUM, V](0.0, quantity, cut.zero)
162 | def +(that: Selecting[DATUM, V]) =
163 | if (this.quantity.name != that.quantity.name)
164 | throw new ContainerException(s"cannot add ${getClass.getName} because quantity name differs (${this.quantity.name} vs ${that.quantity.name})")
165 | else
166 | new Selecting[DATUM, V](this.entries + that.entries, this.quantity, this.cut + that.cut)
167 | def *(factor: Double) =
168 | if (factor.isNaN || factor <= 0.0)
169 | zero
170 | else
171 | new Selecting[DATUM, V](factor * entries, quantity, cut * factor)
172 |
173 | def fill[SUB <: Datum](datum: SUB, weight: Double = 1.0): Unit = {
174 | checkForCrossReferences()
175 | if (weight > 0.0) {
176 | val w = weight * quantity(datum)
177 | if (w > 0.0)
178 | cut.fill(datum, w)
179 |
180 | // no possibility of exception from here on out (for rollback)
181 | entries += weight
182 | }
183 | }
184 |
185 | def children = cut :: Nil
186 |
187 | def toJsonFragment(suppressName: Boolean) = JsonObject(
188 | "entries" -> JsonFloat(entries),
189 | "sub:type" -> JsonString(cut.factory.name),
190 | "data" -> cut.toJsonFragment(false)).
191 | maybe(JsonString("name") -> (if (suppressName) None else quantity.name.map(JsonString(_))))
192 |
193 | override def toString() = s""""""
194 | override def equals(that: Any) = that match {
195 | case that: Selecting[DATUM, V] => this.entries === that.entries && this.quantity == that.quantity && this.cut == that.cut
196 | case _ => false
197 | }
198 | override def hashCode() = (entries, quantity, cut).hashCode
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/primitives/sum.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep
16 |
17 | import scala.language.existentials
18 |
19 | import org.dianahep.histogrammar.json._
20 | import org.dianahep.histogrammar.util._
21 |
22 | package histogrammar {
23 | //////////////////////////////////////////////////////////////// Sum/Summed/Summing
24 |
25 | /** Accumulate the (weighted) sum of a given quantity, calculated from the data.
26 | *
27 | * Sum differs from [[org.dianahep.histogrammar.Count]] in that it computes a quantity on the spot, rather than percolating a product of weight metadata from nested primitives. Also unlike weights, the sum can add both positive and negative quantities (weights are always non-negative).
28 | *
29 | * Factory produces mutable [[org.dianahep.histogrammar.Summing]] and immutable [[org.dianahep.histogrammar.Summed]] objects.
30 | */
31 | object Sum extends Factory {
32 | val name = "Sum"
33 | val help = "Accumulate the (weighted) sum of a given quantity, calculated from the data."
34 | val detailedHelp = """Sum differs from [[org.dianahep.histogrammar.Count]] in that it computes a quantity on the spot, rather than percolating a product of weight metadata from nested primitives. Also unlike weights, the sum can add both positive and negative quantities (weights are always non-negative)."""
35 |
36 | /** Create an immutable [[org.dianahep.histogrammar.Summed]] from arguments (instead of JSON).
37 | *
38 | * @param entries Weighted number of entries (sum of all observed weights).
39 | * @param sum The sum of weight times quantity over all entries.
40 | */
41 | def ed(entries: Double, sum: Double) = new Summed(entries, None, sum)
42 |
43 | /** Create an empty, mutable [[org.dianahep.histogrammar.Summing]].
44 | *
45 | * @param quantity Numerical function to track.
46 | */
47 | def apply[DATUM](quantity: UserFcn[DATUM, Double]) = new Summing[DATUM](quantity, 0.0, 0.0)
48 |
49 | /** Synonym for `apply`. */
50 | def ing[DATUM](quantity: UserFcn[DATUM, Double]) = apply(quantity)
51 |
52 | /** Use [[org.dianahep.histogrammar.Summed]] in Scala pattern-matching. */
53 | def unapply(x: Summed) = Some(x.sum)
54 | /** Use [[org.dianahep.histogrammar.Summing]] in Scala pattern-matching. */
55 | def unapply(x: Summing[_]) = Some(x.sum)
56 |
57 | import KeySetComparisons._
58 | def fromJsonFragment(json: Json, nameFromParent: Option[String]): Container[_] with NoAggregation = json match {
59 | case JsonObject(pairs @ _*) if (pairs.keySet has Set("entries", "sum").maybe("name")) =>
60 | val get = pairs.toMap
61 |
62 | val entries = get("entries") match {
63 | case JsonNumber(x) => x
64 | case x => throw new JsonFormatException(x, name + ".entries")
65 | }
66 |
67 | val quantityName = get.getOrElse("name", JsonNull) match {
68 | case JsonString(x) => Some(x)
69 | case JsonNull => None
70 | case x => throw new JsonFormatException(x, name + ".name")
71 | }
72 |
73 | val sum = get("sum") match {
74 | case JsonNumber(x) => x
75 | case x => throw new JsonFormatException(x, name + ".sum")
76 | }
77 |
78 | new Summed(entries, (nameFromParent ++ quantityName).lastOption, sum)
79 |
80 | case _ => throw new JsonFormatException(json, name)
81 | }
82 | }
83 |
84 | /** An accumulated weighted sum of a given quantity.
85 | *
86 | * Use the factory [[org.dianahep.histogrammar.Sum]] to construct an instance.
87 | *
88 | * @param entries Weighted number of entries (sum of all observed weights).
89 | * @param quantityName Optional name given to the quantity function, passed for bookkeeping.
90 | * @param sum The sum of weight times quantity over all entries.
91 | */
92 | class Summed private[histogrammar](val entries: Double, val quantityName: Option[String], val sum: Double) extends Container[Summed] with NoAggregation with QuantityName {
93 | type Type = Summed
94 | type EdType = Summed
95 | def factory = Sum
96 |
97 | def zero = new Summed(0.0, quantityName, 0.0)
98 | def +(that: Summed) =
99 | if (this.quantityName != that.quantityName)
100 | throw new ContainerException(s"cannot add ${getClass.getName} because quantityName differs (${this.quantityName} vs ${that.quantityName})")
101 | else
102 | new Summed(this.entries + that.entries, this.quantityName, this.sum + that.sum)
103 | def *(factor: Double) =
104 | if (factor.isNaN || factor <= 0.0)
105 | zero
106 | else
107 | new Summed(factor * entries, quantityName, factor * sum)
108 |
109 | def children = Nil
110 |
111 | def toJsonFragment(suppressName: Boolean) = JsonObject(
112 | "entries" -> JsonFloat(entries),
113 | "sum" -> JsonFloat(sum)).
114 | maybe(JsonString("name") -> (if (suppressName) None else quantityName.map(JsonString(_))))
115 |
116 | override def toString() = s""
117 | override def equals(that: Any) = that match {
118 | case that: Summed => this.entries === that.entries && this.quantityName == that.quantityName && this.sum === that.sum
119 | case _ => false
120 | }
121 | override def hashCode() = (entries, quantityName, sum).hashCode
122 | }
123 |
124 | /** Accumulating a weighted sum of a given quantity.
125 | *
126 | * Use the factory [[org.dianahep.histogrammar.Sum]] to construct an instance.
127 | *
128 | * @param quantity Numerical function to track.
129 | * @param entries Weighted number of entries (sum of all observed weights).
130 | * @param sum The sum of weight times quantity over all entries.
131 | */
132 | class Summing[DATUM] private[histogrammar](val quantity: UserFcn[DATUM, Double], var entries: Double, var sum: Double) extends Container[Summing[DATUM]] with AggregationOnData with NumericalQuantity[DATUM] {
133 | type Type = Summing[DATUM]
134 | type EdType = Summed
135 | type Datum = DATUM
136 | def factory = Sum
137 |
138 | def zero = new Summing[DATUM](quantity, 0.0, 0.0)
139 | def +(that: Summing[DATUM]) =
140 | if (this.quantity.name != that.quantity.name)
141 | throw new ContainerException(s"cannot add ${getClass.getName} because quantity name differs (${this.quantity.name} vs ${that.quantity.name})")
142 | else
143 | new Summing(this.quantity, this.entries + that.entries, this.sum + that.sum)
144 | def *(factor: Double) =
145 | if (factor.isNaN || factor <= 0.0)
146 | zero
147 | else
148 | new Summing[DATUM](quantity, factor * entries, factor * sum)
149 |
150 | def fill[SUB <: Datum](datum: SUB, weight: Double = 1.0): Unit = {
151 | checkForCrossReferences()
152 | if (weight > 0.0) {
153 | val q = quantity(datum)
154 |
155 | // no possibility of exception from here on out (for rollback)
156 | entries += weight
157 | sum += q * weight
158 | }
159 | }
160 |
161 | def children = Nil
162 |
163 | def toJsonFragment(suppressName: Boolean) = JsonObject(
164 | "entries" -> JsonFloat(entries),
165 | "sum" -> JsonFloat(sum)).
166 | maybe(JsonString("name") -> (if (suppressName) None else quantity.name.map(JsonString(_))))
167 |
168 | override def toString() = s""
169 | override def equals(that: Any) = that match {
170 | case that: Summing[DATUM] => this.quantity == that.quantity && this.entries === that.entries && this.sum === that.sum
171 | case _ => false
172 | }
173 | override def hashCode() = (quantity, entries, sum).hashCode
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/tutorial/cmsdata.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep.histogrammar.tutorial
16 |
17 | /**
18 | * Most of the examples must use some dataset, so I prepared a sample of CMS public data to be read with no dependencies. The data came from the CERN Open Data portal; it is 50 fb-1 of highly processed particle physics data from the CMS experiment, with 469,384 events selected by the 24 GeV/c isolated muon trigger.
19 | *
20 | * For convenience, it has been converted to compressed JSON. The code that reads it into classes is provided below for you to copy-paste, rather than a JAR to load, because I want you to see how it’s done and you may want to modify it.
21 | */
22 | package cmsdata {
23 | // class definitions
24 |
25 | trait LorentzVector extends Serializable {
26 | // abstract members; must be defined by subclasses
27 | def px: Double
28 | def py: Double
29 | def pz: Double
30 | def E: Double
31 |
32 | // methods common to all LorentzVectors
33 | def pt = Math.sqrt(px*px + py*py)
34 | def p = Math.sqrt(px*px + py*py + pz*pz)
35 | def mass = Math.sqrt(E*E - px*px - py*py - pz*pz)
36 | def eta = 0.5*Math.log((p + pz)/(p - pz))
37 | def phi = Math.atan2(py, px)
38 |
39 | // addition operator is a method named "+"
40 | def +(two: LorentzVector) = {
41 | val one = this
42 | // create a subclass and an instance in one block
43 | new LorentzVector {
44 | def px = one.px + two.px
45 | def py = one.py + two.py
46 | def pz = one.pz + two.pz
47 | def E = one.E + two.E
48 | override def toString() = s"LorentzVector($px, $py, $pz, $E)"
49 | }
50 | }
51 | }
52 |
53 | // particle class definitions are now one-liners
54 |
55 | case class Jet(px: Double, py: Double, pz: Double, E: Double, btag: Double) extends LorentzVector
56 |
57 | case class Muon(px: Double, py: Double, pz: Double, E: Double, q: Int, iso: Double) extends LorentzVector
58 |
59 | case class Electron(px: Double, py: Double, pz: Double, E: Double, q: Int, iso: Double) extends LorentzVector
60 |
61 | case class Photon(px: Double, py: Double, pz: Double, E: Double, iso: Double) extends LorentzVector
62 |
63 | case class MET(px: Double, py: Double) {
64 | def pt = Math.sqrt(px*px + py*py)
65 | }
66 |
67 | case class Event(jets: Seq[Jet], muons: Seq[Muon], electrons: Seq[Electron], photons: Seq[Photon], met: MET, numPrimaryVertices: Long)
68 |
69 | // event data iterator
70 | case class EventIterator(location: String = "http://histogrammar.org/docs/data/triggerIsoMu24_50fb-1.json.gz") extends Iterator[Event] {
71 | import org.dianahep.histogrammar.json._
72 |
73 | // use Java libraries to stream and decompress data on-the-fly
74 | @transient val scanner = new java.util.Scanner(
75 | new java.util.zip.GZIPInputStream(
76 | new java.net.URL(location).openStream))
77 |
78 | // read one ahead so that hasNext can effectively "peek"
79 | private def getNext() =
80 | try {
81 | Json.parse(scanner.nextLine) collect {
82 | case event: JsonObject => eventFromJson(event)
83 | }
84 | }
85 | catch {
86 | case err: java.util.NoSuchElementException => None
87 | }
88 |
89 | private var theNext = getNext()
90 |
91 | // iterator interface
92 | def hasNext = !theNext.isEmpty
93 | def next() = {
94 | val out = theNext.get
95 | theNext = getNext()
96 | out
97 | }
98 |
99 | def jetFromJson(params: Map[String, JsonNumber]) =
100 | new Jet(params("px").toDouble,
101 | params("py").toDouble,
102 | params("pz").toDouble,
103 | params("E").toDouble,
104 | params("btag").toDouble)
105 |
106 | def muonFromJson(params: Map[String, JsonNumber]) =
107 | new Muon(params("px").toDouble,
108 | params("py").toDouble,
109 | params("pz").toDouble,
110 | params("E").toDouble,
111 | params("q").toInt,
112 | params("iso").toDouble)
113 |
114 | def electronFromJson(params: Map[String, JsonNumber]) =
115 | new Electron(params("px").toDouble,
116 | params("py").toDouble,
117 | params("pz").toDouble,
118 | params("E").toDouble,
119 | params("q").toInt,
120 | params("iso").toDouble)
121 |
122 | def photonFromJson(params: Map[String, JsonNumber]) =
123 | new Photon(params("px").toDouble,
124 | params("py").toDouble,
125 | params("pz").toDouble,
126 | params("E").toDouble,
127 | params("iso").toDouble)
128 |
129 | def metFromJson(params: Map[String, JsonNumber]): MET =
130 | new MET(params("px").toDouble, params("py").toDouble)
131 |
132 | def eventFromJson(params: JsonObject) = {
133 | val JsonArray(jets @ _*) = params("jets")
134 | val JsonArray(muons @ _*) = params("muons")
135 | val JsonArray(electrons @ _*) = params("electrons")
136 | val JsonArray(photons @ _*) = params("photons")
137 | val met = params("MET").asInstanceOf[JsonObject]
138 | val JsonInt(numPrimaryVertices) = params("numPrimaryVertices")
139 | new Event(
140 | jets collect {case j: JsonObject => jetFromJson(j.to[JsonNumber].toMap)},
141 | muons collect {case j: JsonObject => muonFromJson(j.to[JsonNumber].toMap)},
142 | electrons collect {case j: JsonObject => electronFromJson(j.to[JsonNumber].toMap)},
143 | photons collect {case j: JsonObject => photonFromJson(j.to[JsonNumber].toMap)},
144 | metFromJson(met.to[JsonNumber].toMap),
145 | numPrimaryVertices)
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/core/src/main/scala/org/dianahep/histogrammar/util.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2016 DIANA-HEP
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package org.dianahep.histogrammar
16 |
17 | import scala.util.Random
18 |
19 | import scala.collection.SortedMap
20 | import scala.collection.SortedSet
21 |
22 | import org.dianahep.histogrammar._
23 |
24 | /** Supporting functions, mostly called by those in [[org.dianahep.histogrammar]]. */
25 | package object util {
26 | // /** The natural [[org.dianahep.histogrammar.util.MetricOrdering]] for `Double` precision numbers. */
27 | // implicit val doubleOrdering: MetricOrdering[Double] = new MetricOrdering[Double] {
28 | // def difference(x: Double, y: Double) = x - y
29 | // }
30 |
31 | /** Relative tolerance for numerical equality. Only affects `equals` checks, not `fill` or `+`. */
32 | var relativeTolerance: Double = 0.0
33 | /** Absolute tolerance for numerical equality. Only affects `equals` checks, not `fill` or `+`. */
34 | var absoluteTolerance: Double = 0.0
35 | }
36 |
37 | package util {
38 | //////////////////////////////////////////////////////////////// type-level programming to test compatibility of user-defined functions
39 |
40 | private[histogrammar] trait Compatible[-X, -Y]
41 | private[histogrammar] object Compatible {
42 | implicit object BothAreCounting extends Compatible[Counting, Counting]
43 | implicit object XIsCounting extends Compatible[Counting, AggregationOnData]
44 | implicit object YIsCounting extends Compatible[AggregationOnData, Counting]
45 | implicit def dataAreCompatible[X <: AggregationOnData, Y <: AggregationOnData](implicit evidence: X#Datum =:= Y#Datum) = new Compatible[X, Y] {}
46 | }
47 |
48 | //////////////////////////////////////////////////////////////// handling key set comparisons with optional keys
49 |
50 | object KeySetComparisons {
51 | trait KeySet {
52 | def required: Set[String]
53 | def optional: Set[String]
54 |
55 | def maybe(string: String) = {
56 | val t = this
57 | new KeySet {
58 | def required = t.required
59 | def optional = t.optional ++ Set(string)
60 | }
61 | }
62 | }
63 |
64 | implicit class KeySetFromSet(test: Set[String]) extends KeySet {
65 | def required = test
66 | def optional = Set[String]()
67 | def has(that: KeySet) = (that.required subsetOf test) && (test subsetOf (that.required ++ that.optional))
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
5 | 4.0.0
6 |
7 | histogrammar-parent
8 | Histogrammar parent package. See org.diana-hep:histogrammar for the core functionality.
9 | https://histogrammar.github.io/histogrammar-docs
10 | 2016
11 |
12 | io.github.histogrammar
13 | histogrammar-parent
14 | pom
15 | 1.0.20
16 |
17 |
18 |
19 | Apache License, Version 2.0
20 | http://www.apache.org/licenses/LICENSE-2.0
21 | repo
22 |
23 |
24 |
25 |
26 |
27 | Jim Pivarski
28 | jpivarski@gmail.com
29 | DIANA-HEP
30 | http://diana-hep.org
31 |
32 |
33 |
34 |
35 |
36 | scala-2.10
37 |
38 | true
39 |
40 |
41 | core
42 | sparksql
43 | bokeh
44 |
45 |
46 |
47 | scala-2.11
48 |
49 | scala-2.11
50 |
51 |
52 | core
53 | sparksql
54 |
55 |
56 |
57 |
58 | scala-2.12
59 |
60 | scala-2.12
61 |
62 |
63 | core
64 | sparksql
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | ossrh
73 | https://oss.sonatype.org/content/repositories/snapshots
74 |
75 |
76 | ossrh
77 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
78 |
79 |
80 |
81 |
82 |
83 | central
84 | Central Repository
85 | http://repo1.maven.org/maven2
86 | default
87 |
88 | false
89 |
90 |
91 |
92 |
93 |
94 |
95 | central
96 | Maven Plugin Repository
97 | http://repo1.maven.org/maven2
98 | default
99 |
100 | false
101 |
102 |
103 | never
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/sparksql/deploy-scala-2.10.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | histogrammar-sparksql
19 | Adapter for using Histogrammar in SparkSQL.
20 | http://histogrammar.org
21 | 2016
22 |
23 | org.diana-hep
24 | histogrammar-sparksql_2.10
25 | 1.0.20
26 | jar
27 |
28 |
29 |
30 | Apache License, Version 2.0
31 | http://www.apache.org/licenses/LICENSE-2.0
32 | repo
33 |
34 |
35 |
36 |
37 |
38 | Jim Pivarski
39 | jpivarski@gmail.com
40 | DIANA-HEP
41 | http://diana-hep.org
42 |
43 |
44 |
45 |
46 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
47 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
48 | git@github.com:histogrammar/histogrammar-scala.git
49 |
50 |
51 |
52 |
53 |
54 | org.scala-tools
55 | maven-scala-plugin
56 | 2.15.2
57 |
58 |
59 |
60 |
61 |
62 | UTF-8
63 | UTF-8
64 | 1.7
65 | 1.7
66 |
67 |
68 |
69 |
70 | org.scala-lang
71 | scala-library
72 | 2.10.6
73 |
74 |
75 |
76 | org.diana-hep
77 | histogrammar_2.10
78 | 1.0.4
79 |
80 |
81 |
82 | org.apache.spark
83 | spark-sql_2.10
84 | 1.6.2
85 | provided
86 |
87 |
88 |
89 |
90 |
91 |
92 | central
93 | Central Repository
94 | http://repo1.maven.org/maven2
95 | default
96 |
97 | false
98 |
99 |
100 |
101 |
102 |
103 |
104 | central
105 | Maven Plugin Repository
106 | http://repo1.maven.org/maven2
107 | default
108 |
109 | false
110 |
111 |
112 | never
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | net.alchim31.maven
123 | scala-maven-plugin
124 | 3.2.2
125 |
126 |
127 |
128 | compile
129 | testCompile
130 |
131 |
132 |
133 | -Dscalac.patmat.analysisBudget=512
134 | -deprecation
135 | -feature
136 | -unchecked
137 | -dependencyfile
138 | ${project.build.directory}/.scala_dependencies
139 |
140 | incremental
141 |
142 |
143 |
144 |
145 | attach-sources
146 |
147 | add-source
148 |
149 |
150 |
151 | attach-javadocs
152 |
153 | doc-jar
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-install-plugin
163 | 2.5.2
164 |
165 | true
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-source-plugin
172 | 2.2.1
173 |
174 |
175 | attach-sources
176 |
177 | jar-no-fork
178 |
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-gpg-plugin
186 | 1.6
187 |
188 |
189 | sign-artifacts
190 | verify
191 |
192 | sign
193 |
194 |
195 |
196 |
197 |
198 |
199 | org.sonatype.plugins
200 | nexus-staging-maven-plugin
201 | 1.6.7
202 | true
203 |
204 | ossrh
205 | https://oss.sonatype.org/
206 | true
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | org.apache.maven.plugins
216 | maven-release-plugin
217 | 2.5
218 |
219 | false
220 | false
221 | true
222 | deploy
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | ossrh
238 | https://oss.sonatype.org/content/repositories/snapshots
239 |
240 |
241 | ossrh
242 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/sparksql/deploy-scala-2.11.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | histogrammar-sparksql
19 | Adapter for using Histogrammar in SparkSQL.
20 | https://histogrammar.github.io/histogrammar-docs
21 | 2016
22 |
23 | io.github.histogrammar
24 | histogrammar-sparksql_2.11
25 | 1.0.20
26 | jar
27 |
28 |
29 |
30 | Apache License, Version 2.0
31 | http://www.apache.org/licenses/LICENSE-2.0
32 | repo
33 |
34 |
35 |
36 |
37 |
38 | Jim Pivarski
39 | jpivarski@gmail.com
40 | DIANA-HEP
41 | http://diana-hep.org
42 |
43 |
44 |
45 |
46 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
47 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
48 | git@github.com:histogrammar/histogrammar-scala.git
49 |
50 |
51 |
52 |
53 |
54 | org.scala-tools
55 | maven-scala-plugin
56 | 2.15.2
57 |
58 |
59 |
60 |
61 |
62 | UTF-8
63 | UTF-8
64 | 1.8
65 | 1.8
66 |
67 |
68 |
69 |
70 | org.scala-lang
71 | scala-library
72 | 2.11.12
73 |
74 |
75 |
76 | io.github.histogrammar
77 | histogrammar_2.11
78 | 1.0.11
79 |
80 |
81 |
82 | org.apache.spark
83 | spark-sql_2.11
84 | 2.0.0
85 | provided
86 |
87 |
88 |
89 |
90 |
91 |
92 | central
93 | Central Repository
94 | http://repo1.maven.org/maven2
95 | default
96 |
97 | false
98 |
99 |
100 |
101 |
102 |
103 |
104 | central
105 | Maven Plugin Repository
106 | http://repo1.maven.org/maven2
107 | default
108 |
109 | false
110 |
111 |
112 | never
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | net.alchim31.maven
123 | scala-maven-plugin
124 | 4.4.0
125 |
126 |
127 |
128 | compile
129 | testCompile
130 |
131 |
132 |
133 | -Dscalac.patmat.analysisBudget=512
134 | -deprecation
135 | -feature
136 | -unchecked
137 | -dependencyfile
138 | ${project.build.directory}/.scala_dependencies
139 |
140 | incremental
141 |
142 |
143 |
144 |
145 | attach-sources
146 |
147 | add-source
148 |
149 |
150 |
151 | attach-javadocs
152 |
153 | doc-jar
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-install-plugin
163 | 2.5.2
164 |
165 | true
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-source-plugin
172 | 2.2.1
173 |
174 |
175 | attach-sources
176 |
177 | jar-no-fork
178 |
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-gpg-plugin
186 | 1.5
187 |
188 |
189 | sign-artifacts
190 | verify
191 |
192 | sign
193 |
194 |
195 |
196 |
197 |
198 |
199 | org.sonatype.plugins
200 | nexus-staging-maven-plugin
201 | 1.6.7
202 | true
203 |
204 | ossrh
205 | https://oss.sonatype.org/
206 | true
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | org.apache.maven.plugins
216 | maven-release-plugin
217 | 2.5
218 |
219 | false
220 | false
221 | true
222 | deploy
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | ossrh
238 | https://oss.sonatype.org/content/repositories/snapshots
239 |
240 |
241 | ossrh
242 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/sparksql/deploy-scala-2.12.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | histogrammar-sparksql
19 | Adapter for using Histogrammar in SparkSQL.
20 | https://histogrammar.github.io/histogrammar-docs
21 | 2016
22 |
23 | io.github.histogrammar
24 | histogrammar-sparksql_2.12
25 | 1.0.30
26 | jar
27 |
28 |
29 |
30 | Apache License, Version 2.0
31 | http://www.apache.org/licenses/LICENSE-2.0
32 | repo
33 |
34 |
35 |
36 |
37 |
38 | Jim Pivarski
39 | jpivarski@gmail.com
40 | DIANA-HEP
41 | http://diana-hep.org
42 |
43 |
44 |
45 |
46 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
47 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
48 | git@github.com:histogrammar/histogrammar-scala.git
49 |
50 |
51 |
52 |
53 |
54 | org.scala-tools
55 | maven-scala-plugin
56 | 2.15.2
57 |
58 |
59 |
60 |
61 |
62 | UTF-8
63 | UTF-8
64 | 1.8
65 | 1.8
66 |
67 |
68 |
69 |
70 | org.scala-lang
71 | scala-library
72 | 2.12.13
73 |
74 |
75 |
76 | io.github.histogrammar
77 | histogrammar_2.12
78 | 1.0.30
79 |
80 |
81 |
82 | org.apache.spark
83 | spark-sql_2.12
84 | 3.0.1
85 | provided
86 |
87 |
88 |
89 |
90 |
91 |
92 | central
93 | Central Repository
94 | http://repo1.maven.org/maven2
95 | default
96 |
97 | false
98 |
99 |
100 |
101 |
102 |
103 |
104 | central
105 | Maven Plugin Repository
106 | http://repo1.maven.org/maven2
107 | default
108 |
109 | false
110 |
111 |
112 | never
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | net.alchim31.maven
123 | scala-maven-plugin
124 | 4.4.0
125 |
126 |
127 |
128 | compile
129 | testCompile
130 |
131 |
132 |
133 | -Dscalac.patmat.analysisBudget=512
134 | -deprecation
135 | -feature
136 | -unchecked
137 | -dependencyfile
138 | ${project.build.directory}/.scala_dependencies
139 |
140 | incremental
141 |
142 |
143 |
144 |
145 | attach-sources
146 |
147 | add-source
148 |
149 |
150 |
151 | attach-javadocs
152 |
153 | doc-jar
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-install-plugin
163 | 2.5.2
164 |
165 | true
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-source-plugin
172 | 2.2.1
173 |
174 |
175 | attach-sources
176 |
177 | jar-no-fork
178 |
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-gpg-plugin
186 | 1.5
187 |
188 |
189 | sign-artifacts
190 | verify
191 |
192 | sign
193 |
194 |
195 |
196 |
197 |
198 |
199 | org.sonatype.plugins
200 | nexus-staging-maven-plugin
201 | 1.6.13
202 | true
203 |
204 | ossrh
205 | https://oss.sonatype.org/
206 | true
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | org.apache.maven.plugins
216 | maven-release-plugin
217 | 3.0.1
218 |
219 | false
220 | false
221 | true
222 | deploy
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | ossrh
238 | https://oss.sonatype.org/content/repositories/snapshots
239 |
240 |
241 | ossrh
242 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/sparksql/deploy-scala-2.13.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | histogrammar-sparksql
19 | Adapter for using Histogrammar in SparkSQL.
20 | https://histogrammar.github.io/histogrammar-docs
21 | 2016
22 |
23 | io.github.histogrammar
24 | histogrammar-sparksql_2.13
25 | 1.0.30
26 | jar
27 |
28 |
29 |
30 | Apache License, Version 2.0
31 | http://www.apache.org/licenses/LICENSE-2.0
32 | repo
33 |
34 |
35 |
36 |
37 |
38 | Jim Pivarski
39 | jpivarski@gmail.com
40 | DIANA-HEP
41 | http://diana-hep.org
42 |
43 |
44 |
45 |
46 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
47 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
48 | git@github.com:histogrammar/histogrammar-scala.git
49 |
50 |
51 |
52 |
53 |
54 | org.scala-tools
55 | maven-scala-plugin
56 | 2.15.2
57 |
58 |
59 |
60 |
61 |
62 | UTF-8
63 | UTF-8
64 | 1.8
65 | 1.8
66 |
67 |
68 |
69 |
70 | org.scala-lang
71 | scala-library
72 | 2.13.12
73 |
74 |
75 |
76 | io.github.histogrammar
77 | histogrammar_2.13
78 | 1.0.30
79 |
80 |
81 |
82 | org.apache.spark
83 | spark-sql_2.13
84 | 3.4.2
85 | provided
86 |
87 |
88 |
89 |
90 |
91 |
92 | central
93 | Central Repository
94 | http://repo1.maven.org/maven2
95 | default
96 |
97 | false
98 |
99 |
100 |
101 |
102 |
103 |
104 | central
105 | Maven Plugin Repository
106 | http://repo1.maven.org/maven2
107 | default
108 |
109 | false
110 |
111 |
112 | never
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | net.alchim31.maven
123 | scala-maven-plugin
124 | 4.4.0
125 |
126 |
127 |
128 | compile
129 | testCompile
130 |
131 |
132 |
133 | -Dscalac.patmat.analysisBudget=512
134 | -deprecation
135 | -feature
136 | -unchecked
137 | -dependencyfile
138 | ${project.build.directory}/.scala_dependencies
139 |
140 | incremental
141 |
142 |
143 |
144 |
145 | attach-sources
146 |
147 | add-source
148 |
149 |
150 |
151 | attach-javadocs
152 |
153 | doc-jar
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-install-plugin
163 | 2.5.2
164 |
165 | true
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-source-plugin
172 | 2.2.1
173 |
174 |
175 | attach-sources
176 |
177 | jar-no-fork
178 |
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-gpg-plugin
186 | 1.5
187 |
188 |
189 | sign-artifacts
190 | verify
191 |
192 | sign
193 |
194 |
195 |
196 |
197 |
198 |
199 | org.sonatype.plugins
200 | nexus-staging-maven-plugin
201 | 1.6.13
202 | true
203 |
204 | ossrh
205 | https://oss.sonatype.org/
206 | true
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | org.apache.maven.plugins
216 | maven-release-plugin
217 | 3.0.1
218 |
219 | false
220 | false
221 | true
222 | deploy
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | ossrh
238 | https://oss.sonatype.org/content/repositories/snapshots
239 |
240 |
241 | ossrh
242 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/sparksql/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | histogrammar-sparksql
19 | Adapter for using Histogrammar in SparkSQL.
20 | https://histogrammar.github.io/histogrammar-docs
21 | 2016
22 |
23 | io.github.histogrammar
24 | histogrammar-sparksql_${scala.binary.version}
25 | 1.0.30
26 | jar
27 |
28 |
29 |
30 | Apache License, Version 2.0
31 | http://www.apache.org/licenses/LICENSE-2.0
32 | repo
33 |
34 |
35 |
36 |
37 |
38 | Jim Pivarski
39 | jpivarski@gmail.com
40 | DIANA-HEP
41 | http://diana-hep.org
42 |
43 |
44 |
45 |
46 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
47 | scm:git:git@github.com:histogrammar/histogrammar-scala.git
48 | git@github.com:histogrammar/histogrammar-scala.git
49 |
50 |
51 |
52 |
53 | scala-2.10
54 |
55 | true
56 |
57 |
58 | 2.10.6
59 | 2.10
60 | 1.7
61 | 1.7
62 | 1.6.2
63 | 8
64 |
65 |
66 |
67 |
68 | scala-2.11
69 |
70 | scala-2.11
71 |
72 |
73 | 2.11.12
74 | 2.11
75 | 1.8
76 | 1.8
77 | 2.0.0
78 | 8
79 |
80 |
81 |
82 |
83 | scala-2.12
84 |
85 | scala-2.12
86 |
87 |
88 | 2.12.13
89 | 2.12
90 | 11
91 | 11
92 | 3.0.1
93 | 11
94 |
95 |
96 |
97 |
98 | scala-2.13
99 |
100 | scala-2.13
101 |
102 |
103 | 2.13.0
104 | 2.13
105 | 11
106 | 11
107 | 3.2.0
108 | 11
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | org.scala-tools
118 | maven-scala-plugin
119 | 2.15.2
120 |
121 |
122 |
123 |
124 |
125 | UTF-8
126 | UTF-8
127 |
128 |
129 |
130 |
131 | org.scala-lang
132 | scala-library
133 | ${scala.version}
134 |
135 |
136 |
137 | io.github.histogrammar
138 | histogrammar_${scala.binary.version}
139 | 1.0.20
140 |
141 |
142 |
143 | org.apache.spark
144 | spark-sql_${scala.binary.version}
145 | ${spark.version}
146 | provided
147 |
148 |
149 |
150 |
151 |
152 |
153 | central
154 | Central Repository
155 | https://repo1.maven.org/maven2
156 | default
157 |
158 | false
159 |
160 |
161 |
162 |
163 |
164 |
165 | central
166 | Maven Plugin Repository
167 | https://repo1.maven.org/maven2
168 | default
169 |
170 | false
171 |
172 |
173 | never
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | maven-compiler-plugin
183 | 3.8.1
184 |
185 | 11
186 | 11
187 |
188 |
189 |
190 |
191 |
192 | net.alchim31.maven
193 | scala-maven-plugin
194 | 4.4.0
195 |
196 |
197 |
198 | compile
199 | testCompile
200 |
201 |
202 |
203 | -Dscalac.patmat.analysisBudget=512
204 | -deprecation
205 | -feature
206 | -unchecked
207 | -dependencyfile
208 | ${project.build.directory}/.scala_dependencies
209 |
210 | incremental
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 | org.apache.maven.plugins
220 | maven-dependency-plugin
221 | 2.10
222 |
223 |
224 | package
225 |
226 | copy-dependencies
227 |
228 |
229 |
230 | target/lib
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | maven-install-plugin
239 | 2.5.2
240 |
241 | true
242 |
243 |
244 |
245 |
246 | org.apache.maven.plugins
247 | maven-source-plugin
248 | 3.2.0
249 |
250 |
251 | attach-sources
252 |
253 | jar
254 |
255 |
256 |
257 |
258 |
259 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
--------------------------------------------------------------------------------