I am trying to define a simple Scala method to determine if two rectangles overlap in any capacity. I believe the way to do this would be something along the lines of:
if (! (Range_of_rectangle1.contains(anything in Range_of_rectangle2) ) ) => false
And this would need to be done for both the x-axis and the y-axis...
But I'm new enough to Scala that I don't sure how to write something like someRange.contains( anything in another Range).
The code I have currently for determining the overlap sorta works but has some problems, as I will discuss:
First I define a Rectangle (and there is a reason that its a case class in my code, but that's unrelated to this task).
case class Rectangle (minx: Int, maxx: Int, miny: Int, maxy: Int)
Then I create the function to look if two rectangles overlap
def rectanglesOverlap(r1: Rectangle, r2:Rectangle): Boolean = {
r2 match {
//In English: if r2's minx OR miny are not anywhere in the range of r1's x-axis, then there's no overlap along the x-axis
//If the range of r1's x-axis does NOT contain anything from r2's x-axis, they don't overlap
case x_overlap1 if (! ( (r1.minx to r1.maxx).contains(r2.minx) || (r1.minx to r1.maxx).contains(r2.maxx) ) ) => false //where r1 is larger rectangle
case y_overlap1 if (! ( (r1.miny to r1.maxy).contains(r2.miny) || (r1.miny to r1.maxy).contains(r2.maxy) ) ) => false
//If the range of r2's x-axis does NOT contain anything from r1's x-axis, they don't overlap
case x_overlap2 if (! ( (r2.minx to r2.maxx).contains(r1.minx) || (r2.minx to r2.maxx).contains(r1.maxx) ) ) => false //where r2 is larger rectangle
case y_overlap2 if (! ( (r2.miny to r2.maxy).contains(r1.miny) || (r2.miny to r2.maxy).contains(r1.maxy) ) ) => false
case _ => true
}
}
So what the code tries to do is start with the x- and y-axis of one of the rectangles, and check if the other rectangle's minx/y OR maxx/y is in there....
See the problem?
When I tested it, I got "false" for this:
val q1 = Rectangle(1, 18, 1, 18)
val q2 = Rectangle(1,8,8,16)
scala> rectanglesOverlap(q1, q2)
res0: Boolean = false
And the reason for this is obvious. Its false because the q2 y-axis is 8-16 and neither q1 miny (1) or q1 maxy (18) fall within the 8-16 range. However, its clear that they overlap.
So know that I conceptually know what's wrong with my code, I'm trying to figure out how to programmatically do something like this:
someRange.contains( anything in another Range).
But my efforts of searching Google and Stack Overflow haven't yielded the proper solution. Help?
When you want to know where one collection overlaps another, you're looking for their "intersection".
someRange.intersect(anotherRange)
or
(1 to 18) intersect (8 to 16)
and to turn it into a Boolean
((1 to 18) intersect (8 to 16)).nonEmpty
Related
I have this:
But I want the x axis to run along y=0, e.g.
And ideally I'd either have the tick labels on top i.e. in the blue bit, or where they were at the bottom of the chart.
EDIT: how the chart is created.
I'm using something like:
var
ndx = crossfilter(data),
dataDimension = ndx.dimension(d => d.period),
ordinals = data.map(d => d.period),
lossGroup = dataDimension.group().reduceSum(d => d.loss),
offsets = lossGroup.all().map(d => -d.value),
chart;
// The data is like {
// period: Date (start of period, e.g. month),
// start: Integer (number at start of period/end of last period)
// loss: Integer (number lost during period)
// gain: Integer (number gained during period)
// }
chart = dc.barChart(chartElement)
.dimension(dataDimension)
// The first group is the loss
.group(lossGroup)
.stack(dataDimension.group().reduceSum(d => d.start), 'carryforward')
.stack(dataDimension.group().reduceSum(d => d.gain), 'gain')
.stackLayout(d3.layout.stack().offset(layers => offsets))
.x(d3.scale.ordinal(ordinals).domain(ordinals))
.xUnits(dc.units.ordinal)
.elasticY(true)
.renderLabel(false)
// The first group is the loss
.title(item => 'Loss: ' + item.value)
.title('carryforward', item => 'Sustained: ' + item.value)
.title('gain', item => 'Gain: ' + item.value)
.renderTitle(true);
dc.renderAll();
Hmm, I guess you are using .stackLayout() to get the negative stacking. Since dc.js doesn't “look inside” this setting, I don't think there is anything built-in to offset the axis. You would probably need to use a pretransition handler to move it.
As for moving the tick labels, you could use .title() instead, like in this example. And then set the tick label to empty.
Best I can think of, not really an answer but more than a comment. :-)
I have say 100 elements that I want to assign to say 10 spots.
# the elements list holds 100 variables that signify the assignment to a spot
elements = [model.NewIntVar(1, 10) for i in range(100)]
Each of my element has a specific size. Now I want to model one (set of) constraint(s) per spot that says: The added sizes of all elements assigned to this spot lies in a fixed range.
So if spot 1 gets elements 1, 16 and 64 assigned, and their sizes are 1521, 1732, 1431 and my range is (3000, 6000) that would be ok. But if too many or too large elements (or too few/small) get assigned to spot 1, that would not be ok.
Something like the following, which does not work:
for spot in range(10):
sum_ = sum([get_size(e) for e in elements if e == spot]) # if think if e == spot is what fails
model.Add(sum_ >= 3000)
model.Add(sum_ <= 6000)
How can I model such a thing? I have looked at channeling constraints but I can't quite wrap my head around it.
I think it is better to model the assignment as a boolean:
from ortools.sat.python import cp_model
model = cp_model.CpModel()
solver = cp_model.CpSolver()
all_spots = range(10)
all_elems = range(100)
elements = {
(elem, spot): model.NewBoolVar(f"{elem} in spot {spot}")
for elem in all_elems
for spot in all_spots
}
# only one spot for element
for elem in all_elems:
model.Add(sum(elements[elem, spot] for spot in all_spots) == 1)
for spot in all_spots:
# taking the element id as its size
sum_ = sum(elements[elem, spot] * elem for elem in all_elems)
model.Add(sum_ >= 0)
model.Add(sum_ <= 500)
solver.Solve(model)
for (elem, spot), boolean in elements.items():
if solver.Value(boolean):
print(boolean)
See:
https://github.com/google/or-tools/blob/stable/ortools/sat/samples/multiple_knapsack_sat.py
https://github.com/google/or-tools/blob/stable/ortools/sat/samples/binpacking_problem_sat.py
https://github.com/google/or-tools/blob/stable/examples/python/balance_group_sat.py#L102
I was looking for Scala's equivalent code or underlying theory for pythons np.random.choice (Numpy as np). I have a similar implementation that uses Python's np.random.choice method to select the random moves from the probability distribution.
Python's code
Input list: ['pooh', 'rabbit', 'piglet', 'Christopher'] and probabilies: [0.5, 0.1, 0.1, 0.3]
I want to select one of the value from the input list given the associated probability of each input element.
The Scala standard library has no equivalent to np.random.choice but it shouldn't be too difficult to build your own, depending on which options/features you want to emulate.
Here, for example, is a way to get an infinite Stream of submitted items, with the probability of any one item weighted relative to the others.
def weightedSelect[T](input :(T,Int)*): Stream[T] = {
val items :Seq[T] = input.flatMap{x => Seq.fill(x._2)(x._1)}
def output :Stream[T] = util.Random.shuffle(items).toStream #::: output
output
}
With this each input item is given with a multiplier. So to get an infinite pseudorandom selection of the characters c and v, with c coming up 3/5ths of the time and v coming up 2/5ths of the time:
val cvs = weightedSelect(('c',3),('v',2))
Thus the rough equivalent of the np.random.choice(aa_milne_arr,5,p=[0.5,0.1,0.1,0.3]) example would be:
weightedSelect("pooh"-> 5
,"rabbit" -> 1
,"piglet" -> 1
,"Christopher" -> 3).take(5).toArray
Or perhaps you want a better (less pseudo) random distribution that might be heavily lopsided.
def weightedSelect[T](items :Seq[T], distribution :Seq[Double]) :Stream[T] = {
assert(items.length == distribution.length)
assert(math.abs(1.0 - distribution.sum) < 0.001) // must be at least close
val dsums :Seq[Double] = distribution.scanLeft(0.0)(_+_).tail
val distro :Seq[Double] = dsums.init :+ 1.1 // close a possible gap
Stream.continually(items(distro.indexWhere(_ > util.Random.nextDouble())))
}
The result is still an infinite Stream of the specified elements but the passed-in arguments are a bit different.
val choices :Stream[String] = weightedSelect( List("this" , "that")
, Array(4998/5000.0, 2/5000.0))
// let's test the distribution
val (choiceA, choiceB) = choices.take(10000).partition(_ == "this")
choiceA.length //res0: Int = 9995
choiceB.length //res1: Int = 5 (not bad)
I'm trying to implement the Boids flocking algorithm in scala in order to learn and improve my functional programming.
I have run into a problem drawing a 'Canvas' on which the birds can move. I need to update the canvas with a "B" representing a boid whenever we print their position.
The Vector2D represents my own implementaion of a 2D Vector which simply contains an x and y position.
The following solution prints only the lines (ie Vectors) on which there is a boid, and repeats this for as many boids as there are. For instance if a list of 3 boids was passed to draw, then nine vectors would be created.
What is required is for canvas boundary amount of vectors to be created (10 in this case) which includes both the lines where there is a boid and those where there isnt.
In more generic form,I have a IndexedSeq of Vectors containing boundary.x amount of a certain value. What I need to do is update a Vector in the IndexedSeq at a certain position in that vector. So if I need to update (1,1) then I would need to update the second vector in the sequence at it's position 1.
Theres a high chance I've missed something obvious so any help on the subject would be greatly appreciated.
Cheers,
David
object Canvas{
val boundary = Vector2D(10,10)
require(boundary.x == boundary.y)
def draw(boids: List[Boid]) = {
val lines = for{
col <- 0 until boundary.x
position <- boids.map(_.position)
} yield Vector.fill(boundary.x)("* ").updated(position.x, "B ")
"\n" + (lines mkString "\n")
}
}
case class Boid (position: Vector2D, velocity: Vector2D){
def this() = this(Vector2D.random,Vector2D.random)
}
case class Vector2D(x: Int, y: Int)
Am trying to determine whether or not to display an overtime game display flag in weekly game results report.
Database game results table has 3 columns (p4,p5,p6) that represent potential overtime game period score total ( for OT, Double OT, and Triple OT respectively). These columns are mapped to Option[Int] in application layer.
Currently I am filtering through game result teamA, teamB pairs, but really I just want to know if an OT game exists of any kind (vs. stepping through the collection).
def overtimeDisplay(a: GameResult, b: GameResult) = {
val isOT = !(List(a,b).filter(_.p4.isDefined).filter(_.p5.isDefined).filter(_.p6.isDefined).isEmpty)
if(isOT) {
<b class="b red">
{List( ((a.p4,a.p5,a.p6),(b.p4,b.p5,b.p6)) ).zipWithIndex.map{
case( ((Some(_),None,None), (Some(_),None,None)), i)=> "OT"
case( ((Some(_),Some(_),None), (Some(_),Some(_),None )), i)=> "Double OT"
case( ((Some(_),Some(_),Some(_)), (Some(_),Some(_),Some(_) )), i)=> "Triple OT"
}}
</b>
}
else scala.xml.NodeSeq.Empty
}
Secondarily, the determination of which type of overtime to display, currently that busy pattern match (which, looking at it now, does not appear cover all the scoring scenarios), could probably be done in a more functional/concise manner.
Feel free to lay it down if you have the better way.
Thanks
Not sure if I understand the initial code correctly, but here is an idea:
val results = List(a, b).map(r => Seq(r.p4, r.p5, r.p6).flatten)
val isOT = results.exists(_.nonEmpty)
val labels = IndexedSeq("", "Double ", "Triple ")
results.map(p => labels(p.size - 1) + "OT")
Turning score column to flat list in first line is crucial here. You have GameResult(p4: Option[Int], p5: Option[Int], p6: Option[Int]) which you can map to Seq[Option[Int]]: r => Seq(r.p4, r.p5, r.p6) and later flatten to turn Some[Int] to Int and get rid of None. This will turn Some(42), None, None into Seq(42).
Looking at this:
val isOT = !(List(a,b).filter(_.p4.isDefined).filter(_.p5.isDefined).filter(_.p6.isDefined).isEmpty)
This can be rewritten using exists instead of filter. I would rewrite it as follows:
List(a, b).exists(x => x.p4.isDefined && x.p5.isDefined && x.p6.isDefined)
In addition to using exists, I am combining the three conditions you passed to the filters into a single anonymous function.
In addition, I don't know why you're using zipWithIndex when it doesn't seem as though you're using the index in the map function afterwards. It could be removed entirely.