1 /***********************************************************************
2  * Copyright (c) 2013-2024 Commonwealth Computer Research, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Apache License, Version 2.0
5  * which accompanies this distribution and is available at
6  * http://www.opensource.org/licenses/apache2.0.php.
7  ***********************************************************************/
8 
9 package org.locationtech.geomesa.utils.stats
10 
11 import com.typesafe.scalalogging.LazyLogging
12 import org.geotools.api.feature.simple.{SimpleFeature, SimpleFeatureType}
13 import org.locationtech.geomesa.curve.TimePeriod.TimePeriod
14 import org.locationtech.geomesa.curve.{BinnedTime, Z3SFC}
15 import org.locationtech.geomesa.utils.clearspring.CountMinSketch
16 import org.locationtech.jts.geom.Geometry
17 
18 import java.util.Date
19 import scala.collection.immutable.ListMap
20 
21 /**
22   * Estimates frequency counts at scale. Tracks geometry and date attributes as a single value.
23   *
24   * @param sft simple feature type
25   * @param geom geometry attribute in the sft
26   * @param dtg date attribute in the sft
27   * @param period time period to use for z index
28   * @param precision number of bits of z-index that will be used
29   * @param eps (epsilon) with probability at least @see confidence, estimates will be within eps * N
30   * @param confidence percent - with probability at least confidence, estimates will be within @see eps * N
31   */
32 class Z3Frequency(
33     val sft: SimpleFeatureType,
34     val geom: String,
35     val dtg: String,
36     val period: TimePeriod,
37     val precision: Int,
38     val eps: Double = 0.005,
39     val confidence: Double = 0.95
40   ) extends Stat with LazyLogging {
41 
42   override type S = Z3Frequency
43 
44   private val g = sft.indexOf(geom)
45   private val d = sft.indexOf(dtg)
46 
47   private val mask = Frequency.getMask(precision)
48   private val sfc = Z3SFC(period)
49   private val timeToBin = BinnedTime.timeToBinnedTime(period)
50 
51   private [stats] val sketches = scala.collection.mutable.Map.empty[Short, CountMinSketch]
52   private [stats] def newSketch: CountMinSketch = CountMinSketch(eps, confidence, Frequency.Seed)
53 
54   private def toKey(geom: Geometry, dtg: Date): (Short, Long) = {
55     import org.locationtech.geomesa.utils.geotools.Conversions.RichGeometry
56     val BinnedTime(b, o) = timeToBin(dtg.getTime)
57     val centroid = geom.safeCentroid()
58     val z = sfc.index(centroid.getX, centroid.getY, o) & mask
59     (b, z)
60   }
61 
62   /**
63     * Gets the count for the given values
64     *
65     * @param geom geometry
66     * @param dtg date
67     * @return count of the values
68     */
69   def count(geom: Geometry, dtg: Date): Long = {
70     val (bin, z3) = toKey(geom, dtg)
71     countDirect(bin, z3)
72   }
73 
74   /**
75     * Gets the count for a time bin and z3. Useful if the values are known ahead of time.
76     *
77     * @param bin period since the epoch
78     * @param z3 z value
79     * @return count of the values
80     */
81   def countDirect(bin: Short, z3: Long): Long = sketches.get(bin).map(_.estimateCount(z3)).getOrElse(0L)
82 
83   /**
84     * Number of observations in the frequency map
85     *
86     * @return number of observations
87     */
88   def size: Long = sketches.values.map(_.size).sum
89 
90   /**
91     * Split the stat into a separate stat per time bin of z data. Allows for separate handling of the reduced
92     * data set.
93     *
94     * @return
95     */
96   def splitByTime: Seq[(Short, Z3Frequency)] = {
97     sketches.toSeq.map { case (w, sketch) =>
98       val freq = new Z3Frequency(sft, geom, dtg, period, precision, eps, confidence)
99       freq.sketches.put(w, sketch)
100       (w, freq)
101     }
102   }
103 
104   override def observe(sf: SimpleFeature): Unit = {
105     val geom = sf.getAttribute(g).asInstanceOf[Geometry]
106     val dtg  = sf.getAttribute(d).asInstanceOf[Date]
107     if (geom != null && dtg != null) {
108       try {
109         val (bin, z3) = toKey(geom, dtg)
110         sketches.getOrElseUpdate(bin, newSketch).add(z3, 1L)
111       } catch {
112         case e: Exception => logger.warn(s"Error observing geom '$geom' and date '$dtg': ${e.toString}")
113       }
114     }
115   }
116 
117   // no-op
118   override def unobserve(sf: SimpleFeature): Unit = {}
119 
120   override def +(other: Z3Frequency): Z3Frequency = {
121     val plus = new Z3Frequency(sft, geom, dtg, period, precision, eps, confidence)
122     plus += this
123     plus += other
124     plus
125   }
126 
127   override def +=(other: Z3Frequency): Unit = {
128     other.sketches.filter(_._2.size > 0).foreach { case (w, sketch) =>
129       sketches.getOrElseUpdate(w, newSketch) += sketch
130     }
131   }
132 
133   override def clear(): Unit = sketches.values.foreach(_.clear())
134 
135   override def isEmpty: Boolean = sketches.values.forall(_.size == 0)
136 
137   override def toJsonObject: Any = {
138     val (e, c) = sketches.values.headOption.map(s => (s.eps, s.confidence)).getOrElse((0d, 0d))
139     ListMap("eps" -> e, "confidence" -> c, "size" -> size)
140   }
141 
142   override def isEquivalent(other: Stat): Boolean = {
143     other match {
144       case s: Z3Frequency =>
145         geom == s.geom && dtg == s.dtg && period == s.period && precision == s.precision && {
146           val nonEmpty = sketches.filter(_._2.size > 0)
147           val sNonEmpty = s.sketches.filter(_._2.size > 0)
148           nonEmpty.keys == sNonEmpty.keys && nonEmpty.keys.forall { k =>
149             sketches(k).isEquivalent(s.sketches(k))
150           }
151         }
152       case _ => false
153     }
154   }
155 }
Line Stmt Id Pos Tree Symbol Tests Code
44 13644 1784 - 1788 Select org.locationtech.geomesa.utils.stats.Z3Frequency.geom Z3Frequency.this.geom
44 13645 1772 - 1789 Apply org.geotools.api.feature.simple.SimpleFeatureType.indexOf Z3Frequency.this.sft.indexOf(Z3Frequency.this.geom)
45 13646 1820 - 1823 Select org.locationtech.geomesa.utils.stats.Z3Frequency.dtg Z3Frequency.this.dtg
45 13647 1808 - 1824 Apply org.geotools.api.feature.simple.SimpleFeatureType.indexOf Z3Frequency.this.sft.indexOf(Z3Frequency.this.dtg)
47 13648 1865 - 1874 Select org.locationtech.geomesa.utils.stats.Z3Frequency.precision Z3Frequency.this.precision
47 13649 1847 - 1875 Apply org.locationtech.geomesa.utils.stats.Frequency.getMask Frequency.getMask(Z3Frequency.this.precision)
48 13650 1902 - 1908 Select org.locationtech.geomesa.utils.stats.Z3Frequency.period Z3Frequency.this.period
48 13651 1896 - 1909 Apply org.locationtech.geomesa.curve.Z3SFC.apply org.locationtech.geomesa.curve.Z3SFC.apply(Z3Frequency.this.period)
49 13652 1964 - 1970 Select org.locationtech.geomesa.utils.stats.Z3Frequency.period Z3Frequency.this.period
49 13653 1936 - 1971 Apply org.locationtech.geomesa.curve.BinnedTime.timeToBinnedTime org.locationtech.geomesa.curve.BinnedTime.timeToBinnedTime(Z3Frequency.this.period)
51 13654 2006 - 2063 TypeApply scala.collection.mutable.Map.empty scala.collection.mutable.Map.empty[Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch]
52 13655 2129 - 2132 Select org.locationtech.geomesa.utils.stats.Z3Frequency.eps Z3Frequency.this.eps
52 13656 2134 - 2144 Select org.locationtech.geomesa.utils.stats.Z3Frequency.confidence Z3Frequency.this.confidence
52 13657 2146 - 2160 Select org.locationtech.geomesa.utils.stats.Frequency.Seed Frequency.Seed
52 13658 2114 - 2161 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.apply(Z3Frequency.this.eps, Z3Frequency.this.confidence, Frequency.Seed)
56 13659 2324 - 2324 Select scala.Tuple2._1 x$1._1
56 13660 2327 - 2327 Select scala.Tuple2._2 x$1._2
57 13661 2374 - 2393 Apply org.locationtech.geomesa.utils.geotools.Conversions.RichGeometry.safeCentroid org.locationtech.geomesa.utils.geotools.Conversions.RichGeometry(geom).safeCentroid()
58 13662 2416 - 2429 Apply org.locationtech.jts.geom.Point.getX centroid.getX()
58 13663 2431 - 2444 Apply org.locationtech.jts.geom.Point.getY centroid.getY()
58 13664 2451 - 2455 Select org.locationtech.geomesa.utils.stats.Z3Frequency.mask Z3Frequency.this.mask
58 13665 2406 - 2455 Apply scala.Long.& Z3Frequency.this.sfc.index(centroid.getX(), centroid.getY(), o, Z3Frequency.this.sfc.index$default$4).&(Z3Frequency.this.mask)
59 13666 2460 - 2466 Apply scala.Tuple2.apply scala.Tuple2.apply[Short, Long](b, z)
70 13667 2674 - 2674 Select scala.Tuple2._1 x$2._1
70 13668 2679 - 2679 Select scala.Tuple2._2 x$2._2
71 13669 2706 - 2726 Apply org.locationtech.geomesa.utils.stats.Z3Frequency.countDirect Z3Frequency.this.countDirect(bin, z3)
81 13670 2987 - 3043 Apply scala.Option.getOrElse Z3Frequency.this.sketches.get(bin).map[Long](((x$3: org.locationtech.geomesa.utils.clearspring.CountMinSketch) => x$3.estimateCount(z3))).getOrElse[Long](0L)
88 13671 3190 - 3196 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.size x$4.size()
88 13672 3189 - 3189 TypeApply scala.collection.Iterable.canBuildFrom collection.this.Iterable.canBuildFrom[Long]
88 13673 3198 - 3198 Select scala.math.Numeric.LongIsIntegral math.this.Numeric.LongIsIntegral
88 13674 3170 - 3201 ApplyToImplicitArgs scala.collection.TraversableOnce.sum Z3Frequency.this.sketches.values.map[Long, Iterable[Long]](((x$4: org.locationtech.geomesa.utils.clearspring.CountMinSketch) => x$4.size()))(collection.this.Iterable.canBuildFrom[Long]).sum[Long](math.this.Numeric.LongIsIntegral)
97 13685 3453 - 3591 Block <nosymbol> { val freq: org.locationtech.geomesa.utils.stats.Z3Frequency = new Z3Frequency(Z3Frequency.this.sft, Z3Frequency.this.geom, Z3Frequency.this.dtg, Z3Frequency.this.period, Z3Frequency.this.precision, Z3Frequency.this.eps, Z3Frequency.this.confidence); freq.sketches.put(w, sketch); scala.Tuple2.apply[Short, org.locationtech.geomesa.utils.stats.Z3Frequency](w, freq) }
97 13686 3434 - 3434 TypeApply scala.collection.Seq.canBuildFrom collection.this.Seq.canBuildFrom[(Short, org.locationtech.geomesa.utils.stats.Z3Frequency)]
97 13687 3415 - 3597 ApplyToImplicitArgs scala.collection.TraversableLike.map Z3Frequency.this.sketches.toSeq.map[(Short, org.locationtech.geomesa.utils.stats.Z3Frequency), Seq[(Short, org.locationtech.geomesa.utils.stats.Z3Frequency)]](((x0$1: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x0$1 match { case (_1: Short, _2: org.locationtech.geomesa.utils.clearspring.CountMinSketch)(Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)((w @ _), (sketch @ _)) => { val freq: org.locationtech.geomesa.utils.stats.Z3Frequency = new Z3Frequency(Z3Frequency.this.sft, Z3Frequency.this.geom, Z3Frequency.this.dtg, Z3Frequency.this.period, Z3Frequency.this.precision, Z3Frequency.this.eps, Z3Frequency.this.confidence); freq.sketches.put(w, sketch); scala.Tuple2.apply[Short, org.locationtech.geomesa.utils.stats.Z3Frequency](w, freq) } }))(collection.this.Seq.canBuildFrom[(Short, org.locationtech.geomesa.utils.stats.Z3Frequency)])
98 13675 3489 - 3492 Select org.locationtech.geomesa.utils.stats.Z3Frequency.sft Z3Frequency.this.sft
98 13676 3494 - 3498 Select org.locationtech.geomesa.utils.stats.Z3Frequency.geom Z3Frequency.this.geom
98 13677 3500 - 3503 Select org.locationtech.geomesa.utils.stats.Z3Frequency.dtg Z3Frequency.this.dtg
98 13678 3505 - 3511 Select org.locationtech.geomesa.utils.stats.Z3Frequency.period Z3Frequency.this.period
98 13679 3513 - 3522 Select org.locationtech.geomesa.utils.stats.Z3Frequency.precision Z3Frequency.this.precision
98 13680 3524 - 3527 Select org.locationtech.geomesa.utils.stats.Z3Frequency.eps Z3Frequency.this.eps
98 13681 3529 - 3539 Select org.locationtech.geomesa.utils.stats.Z3Frequency.confidence Z3Frequency.this.confidence
98 13682 3473 - 3540 Apply org.locationtech.geomesa.utils.stats.Z3Frequency.<init> new Z3Frequency(Z3Frequency.this.sft, Z3Frequency.this.geom, Z3Frequency.this.dtg, Z3Frequency.this.period, Z3Frequency.this.precision, Z3Frequency.this.eps, Z3Frequency.this.confidence)
99 13683 3547 - 3575 Apply scala.collection.mutable.MapLike.put freq.sketches.put(w, sketch)
100 13684 3582 - 3591 Apply scala.Tuple2.apply scala.Tuple2.apply[Short, org.locationtech.geomesa.utils.stats.Z3Frequency](w, freq)
105 13688 3686 - 3687 Select org.locationtech.geomesa.utils.stats.Z3Frequency.g Z3Frequency.this.g
105 13689 3670 - 3711 TypeApply scala.Any.asInstanceOf sf.getAttribute(Z3Frequency.this.g).asInstanceOf[org.locationtech.jts.geom.Geometry]
106 13690 3743 - 3744 Select org.locationtech.geomesa.utils.stats.Z3Frequency.d Z3Frequency.this.d
106 13691 3727 - 3764 TypeApply scala.Any.asInstanceOf sf.getAttribute(Z3Frequency.this.d).asInstanceOf[java.util.Date]
107 13692 3781 - 3785 Literal <nosymbol> null
107 13693 3789 - 3800 Apply java.lang.Object.!= dtg.!=(null)
107 13694 3773 - 3800 Apply scala.Boolean.&& geom.!=(null).&&(dtg.!=(null))
107 13701 3769 - 3769 Literal <nosymbol> ()
107 13702 3769 - 3769 Block <nosymbol> ()
108 13698 3824 - 3917 Block <nosymbol> { <synthetic> <artifact> private[this] val x$5: (Short, Long) = (Z3Frequency.this.toKey(geom, dtg): (Short, Long) @unchecked) match { case (_1: Short, _2: Long)(Short, Long)((bin @ _), (z3 @ _)) => scala.Tuple2.apply[Short, Long](bin, z3) }; val bin: Short = x$5._1; val z3: Long = x$5._2; Z3Frequency.this.sketches.getOrElseUpdate(bin, Z3Frequency.this.newSketch).add(z3, 1L) }
108 13700 3810 - 4046 Try <nosymbol> try { <synthetic> <artifact> private[this] val x$5: (Short, Long) = (Z3Frequency.this.toKey(geom, dtg): (Short, Long) @unchecked) match { case (_1: Short, _2: Long)(Short, Long)((bin @ _), (z3 @ _)) => scala.Tuple2.apply[Short, Long](bin, z3) }; val bin: Short = x$5._1; val z3: Long = x$5._2; Z3Frequency.this.sketches.getOrElseUpdate(bin, Z3Frequency.this.newSketch).add(z3, 1L) } catch { case (e @ (_: Exception)) => (if (Z3Frequency.this.logger.underlying.isWarnEnabled()) Z3Frequency.this.logger.underlying.warn("Error observing geom \'{}\' and date \'{}\': {}", (geom: AnyRef), (dtg: AnyRef), (e.toString(): AnyRef)) else (): Unit) }
109 13695 3829 - 3829 Select scala.Tuple2._1 x$5._1
109 13696 3834 - 3834 Select scala.Tuple2._2 x$5._2
110 13697 3865 - 3917 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.add Z3Frequency.this.sketches.getOrElseUpdate(bin, Z3Frequency.this.newSketch).add(z3, 1L)
112 13699 3963 - 4038 Typed <nosymbol> (if (Z3Frequency.this.logger.underlying.isWarnEnabled()) Z3Frequency.this.logger.underlying.warn("Error observing geom \'{}\' and date \'{}\': {}", (geom: AnyRef), (dtg: AnyRef), (e.toString(): AnyRef)) else (): Unit)
118 13703 4121 - 4123 Literal <nosymbol> ()
121 13704 4210 - 4213 Select org.locationtech.geomesa.utils.stats.Z3Frequency.sft Z3Frequency.this.sft
121 13705 4215 - 4219 Select org.locationtech.geomesa.utils.stats.Z3Frequency.geom Z3Frequency.this.geom
121 13706 4221 - 4224 Select org.locationtech.geomesa.utils.stats.Z3Frequency.dtg Z3Frequency.this.dtg
121 13707 4226 - 4232 Select org.locationtech.geomesa.utils.stats.Z3Frequency.period Z3Frequency.this.period
121 13708 4234 - 4243 Select org.locationtech.geomesa.utils.stats.Z3Frequency.precision Z3Frequency.this.precision
121 13709 4245 - 4248 Select org.locationtech.geomesa.utils.stats.Z3Frequency.eps Z3Frequency.this.eps
121 13710 4250 - 4260 Select org.locationtech.geomesa.utils.stats.Z3Frequency.confidence Z3Frequency.this.confidence
121 13711 4194 - 4261 Apply org.locationtech.geomesa.utils.stats.Z3Frequency.<init> new Z3Frequency(Z3Frequency.this.sft, Z3Frequency.this.geom, Z3Frequency.this.dtg, Z3Frequency.this.period, Z3Frequency.this.precision, Z3Frequency.this.eps, Z3Frequency.this.confidence)
122 13712 4266 - 4278 Apply org.locationtech.geomesa.utils.stats.Z3Frequency.+= plus.+=(this)
123 13713 4283 - 4296 Apply org.locationtech.geomesa.utils.stats.Z3Frequency.+= plus.+=(other)
128 13714 4385 - 4398 Apply scala.Long.> x$6._2.size().>(0)
128 13717 4363 - 4490 Apply scala.collection.IterableLike.foreach other.sketches.filter(((x$6: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$6._2.size().>(0))).foreach[Unit](((x0$1: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x0$1 match { case (_1: Short, _2: org.locationtech.geomesa.utils.clearspring.CountMinSketch)(Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)((w @ _), (sketch @ _)) => Z3Frequency.this.sketches.getOrElseUpdate(w, Z3Frequency.this.newSketch).+=(sketch) }))
129 13715 4436 - 4484 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.+= Z3Frequency.this.sketches.getOrElseUpdate(w, Z3Frequency.this.newSketch).+=(sketch)
129 13716 4436 - 4484 Block org.locationtech.geomesa.utils.clearspring.CountMinSketch.+= Z3Frequency.this.sketches.getOrElseUpdate(w, Z3Frequency.this.newSketch).+=(sketch)
133 13718 4551 - 4560 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.clear x$7.clear()
133 13719 4527 - 4561 Apply scala.collection.IterableLike.foreach Z3Frequency.this.sketches.values.foreach[Unit](((x$7: org.locationtech.geomesa.utils.clearspring.CountMinSketch) => x$7.clear()))
135 13720 4620 - 4631 Apply scala.Long.== x$8.size().==(0)
135 13721 4597 - 4632 Apply scala.collection.IterableLike.forall Z3Frequency.this.sketches.values.forall(((x$8: org.locationtech.geomesa.utils.clearspring.CountMinSketch) => x$8.size().==(0)))
138 13722 4680 - 4680 Select scala.Tuple2._1 x$9._1
138 13723 4683 - 4683 Select scala.Tuple2._2 x$9._2
139 13724 4779 - 4789 Apply scala.Predef.ArrowAssoc.-> scala.Predef.ArrowAssoc[String]("eps").->[Double](e)
139 13725 4791 - 4808 Apply scala.Predef.ArrowAssoc.-> scala.Predef.ArrowAssoc[String]("confidence").->[Double](c)
139 13726 4810 - 4816 Literal <nosymbol> "size"
139 13727 4820 - 4824 Select org.locationtech.geomesa.utils.stats.Z3Frequency.size Z3Frequency.this.size
139 13728 4810 - 4824 Apply scala.Predef.ArrowAssoc.-> scala.Predef.ArrowAssoc[String]("size").->[Long](Z3Frequency.this.size)
139 13729 4771 - 4825 Apply scala.collection.generic.GenMapFactory.apply scala.collection.immutable.ListMap.apply[String, AnyVal](scala.Predef.ArrowAssoc[String]("eps").->[Double](e), scala.Predef.ArrowAssoc[String]("confidence").->[Double](c), scala.Predef.ArrowAssoc[String]("size").->[Long](Z3Frequency.this.size))
145 13730 4948 - 4954 Select org.locationtech.geomesa.utils.stats.Z3Frequency.geom s.geom
145 13731 4965 - 4970 Select org.locationtech.geomesa.utils.stats.Z3Frequency.dtg s.dtg
145 13732 4958 - 4970 Apply java.lang.Object.== Z3Frequency.this.dtg.==(s.dtg)
145 13733 4984 - 4992 Select org.locationtech.geomesa.utils.stats.Z3Frequency.period s.period
145 13734 4974 - 4992 Apply java.lang.Object.== Z3Frequency.this.period.==(s.period)
145 13735 5009 - 5020 Select org.locationtech.geomesa.utils.stats.Z3Frequency.precision s.precision
145 13736 4996 - 5020 Apply scala.Int.== Z3Frequency.this.precision.==(s.precision)
145 13746 4940 - 5287 Apply scala.Boolean.&& Z3Frequency.this.geom.==(s.geom).&&(Z3Frequency.this.dtg.==(s.dtg)).&&(Z3Frequency.this.period.==(s.period)).&&(Z3Frequency.this.precision.==(s.precision)).&&({ val nonEmpty: scala.collection.mutable.Map[Short,org.locationtech.geomesa.utils.clearspring.CountMinSketch] = Z3Frequency.this.sketches.filter(((x$10: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$10._2.size().>(0))); val sNonEmpty: scala.collection.mutable.Map[Short,org.locationtech.geomesa.utils.clearspring.CountMinSketch] = s.sketches.filter(((x$11: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$11._2.size().>(0))); nonEmpty.keys.==(sNonEmpty.keys).&&(nonEmpty.keys.forall(((k: Short) => Z3Frequency.this.sketches.apply(k).isEquivalent(s.sketches.apply(k))))) })
145 13747 4940 - 5287 Block scala.Boolean.&& Z3Frequency.this.geom.==(s.geom).&&(Z3Frequency.this.dtg.==(s.dtg)).&&(Z3Frequency.this.period.==(s.period)).&&(Z3Frequency.this.precision.==(s.precision)).&&({ val nonEmpty: scala.collection.mutable.Map[Short,org.locationtech.geomesa.utils.clearspring.CountMinSketch] = Z3Frequency.this.sketches.filter(((x$10: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$10._2.size().>(0))); val sNonEmpty: scala.collection.mutable.Map[Short,org.locationtech.geomesa.utils.clearspring.CountMinSketch] = s.sketches.filter(((x$11: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$11._2.size().>(0))); nonEmpty.keys.==(sNonEmpty.keys).&&(nonEmpty.keys.forall(((k: Short) => Z3Frequency.this.sketches.apply(k).isEquivalent(s.sketches.apply(k))))) })
146 13737 5067 - 5080 Apply scala.Long.> x$10._2.size().>(0)
146 13738 5051 - 5081 Apply scala.collection.TraversableLike.filter Z3Frequency.this.sketches.filter(((x$10: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$10._2.size().>(0)))
147 13739 5126 - 5139 Apply scala.Long.> x$11._2.size().>(0)
147 13740 5108 - 5140 Apply scala.collection.TraversableLike.filter s.sketches.filter(((x$11: (Short, org.locationtech.geomesa.utils.clearspring.CountMinSketch)) => x$11._2.size().>(0)))
148 13741 5168 - 5182 Select scala.collection.MapLike.keys sNonEmpty.keys
148 13744 5186 - 5277 Apply scala.collection.IterableLike.forall nonEmpty.keys.forall(((k: Short) => Z3Frequency.this.sketches.apply(k).isEquivalent(s.sketches.apply(k))))
148 13745 5151 - 5277 Apply scala.Boolean.&& nonEmpty.keys.==(sNonEmpty.keys).&&(nonEmpty.keys.forall(((k: Short) => Z3Frequency.this.sketches.apply(k).isEquivalent(s.sketches.apply(k)))))
149 13742 5251 - 5264 Apply scala.collection.MapLike.apply s.sketches.apply(k)
149 13743 5226 - 5265 Apply org.locationtech.geomesa.utils.clearspring.CountMinSketch.isEquivalent Z3Frequency.this.sketches.apply(k).isEquivalent(s.sketches.apply(k))
152 13748 5304 - 5309 Literal <nosymbol> false
152 13749 5304 - 5309 Block <nosymbol> false