Boundary Constraint Handling Mechanisms #274
Boundary Constraint Handling Mechanisms #274KyleErwin wants to merge 13 commits intociren:masterfrom KyleErwin:BCHMs
Conversation
|
Is there a reason why the functions are reevaluating the entity? Additionally, this need not be restricted to |
gpampara
left a comment
There was a problem hiding this comment.
There is a bunch of code that seems to be duplicated for the bounds checking, I'd prefer if we extract that to a function and then pass a function in that does the "different" actions.
| if (b) updatePBest(p) else Step.point(p) | ||
| } | ||
|
|
||
| def clamping[S](particle: Particle[S, Double])( |
There was a problem hiding this comment.
This is too specific. We could do better here by ensuring that we don't specialize to Double, instead it would be better if we add a type-param and ensure that there is an Order instance instead so that the comparisons can be done, without caring what the type really is.
| } | ||
|
|
||
| def initToPBAndZeroedVelocity[S](particle: Particle[S, Double])( | ||
| implicit M: HasMemory[S, Double], V: HasVelocity[S, Double]): Step[Double, Particle[S, Double]] = { |
There was a problem hiding this comment.
It seems that composition would be the better strategy here -> could we maybe try see if we can define the zeroing separately and then compose them to get the desired result?
| val newVelocity = updated.map(t => t._2) | ||
|
|
||
| for { | ||
| v <- PSO.updateVelocity(particle, Position.apply(newVelocity, particle.pos.boundary)) |
There was a problem hiding this comment.
We should really use a Lens to do this update instead of recreating the position
| } yield u | ||
| } | ||
|
|
||
| def initToGB[S](particle: Particle[S, Double], gBest: Position[Double])( |
There was a problem hiding this comment.
Let's see if we can generalize this to only need an Order, instead of using Double
|
Okay cool. I'll change it to entity. |
|
@gpampara Ive made the code more generic and simpler. Let me know what you think |
gpampara
left a comment
There was a problem hiding this comment.
This is looking much nicer!
The boundary functions are now no longer related to the PSO / Particle, and should probably be moved out of the pso package and perhaps into Entity? I'm not sure where a good home would be for them. I'm quite pleased that they are in the shape that they are in currently though.
Looking at the code, there is a common pattern that I see emerging. The Position of the entity is modified and then the _vector is then set, with the way that the new vector is constructed being the only real change. I wonder if we should try extract this into a general function, passing in the construction as a function parameter?
|
|
||
| def initToGB[S,A:scalaz.Equal](x: Entity[S,A], gBest: Position[A])(implicit N: spire.math.Numeric[A]) = | ||
| Lenses._position.modify((p: Position[A]) => { | ||
| val c: NonEmptyList[A] = p.pos zip p.boundary zip gBest.pos map {x => flatten(x)} map { |
There was a problem hiding this comment.
The one thing bothering me with this code is that it is partial - this is actually true for all the functions that use the case to match the different options.
The poly function should probably be removed, and we can replace the double map with a single one. For example:
val c: NonEmptyList[A] = p.pos zip p.boundary zip gBest.pos map { case ((p, b), g) =>
if (b.contains(N.toDouble(p))) p else g
}The case in the above is only there to destructure the tuple and is unfortunately a requirement in this usage because the scala compiler is a bit lacking wrt expressive power.
| object PSO { | ||
| import Lenses._ | ||
|
|
||
| trait LowPriorityFlatten extends Poly1 { |
There was a problem hiding this comment.
This should probably be removed.
|
@KyleErwin Please run the code through the scalafmt formater. Can just run |
|
@gpampara formatted the code |
| case t if N.toDouble(t._1) < t._2.lowerValue => N.fromDouble(t._2.lowerValue) | ||
| case t if N.toDouble(t._1) > t._2.upperValue => N.fromDouble(t._2.upperValue) | ||
| case t if t._2.contains(N.toDouble(t._1)) => t._1 | ||
| case t if t._2.contains(N.toDouble(t._1)) => t._1 |
There was a problem hiding this comment.
So, what would be the behavior if t._1 is not contained in t._2? However unlikely that should be? I'm curious as this is a partial function, and they usually bite you later.
There was a problem hiding this comment.
Hmm I see what you're saying. I'll put the first two cases, the greater than and less than cases, in to a parent case that is a doesNotContain. If that makes sense?
|
@gpampara I think I have removed all partial functions. In the partial cases it was simpler to convert them to if-else blocks |
gpampara
left a comment
There was a problem hiding this comment.
It's looking much better!
I think we should adjust the remainder of the functions to also be if-expression based instead of the case statements. They all follow a similar format and the expression means that we are catering for one or another case only.
| def clamp[S, A: scalaz.Equal](x: Entity[S, A])(implicit N: spire.math.Numeric[A]) = | ||
| Lenses._position.modify((p: Position[A]) => { | ||
| val c: NonEmptyList[A] = p.pos.zip(p.boundary).map { | ||
| case (p, b) => { |
There was a problem hiding this comment.
You can lose the curly braces here, seeing as the expression is only an if and always has a resulting value. This if based version is much better imho!
What I means is:
case (p, b) =>
if ....| M: HasMemory[S, A]) = | ||
| Lenses._position.modify((p: Position[A]) => { | ||
| val c: NonEmptyList[A] = p.pos.zip(p.boundary).zip(M._memory.get(x.state).pos).map { | ||
| case ((p, b), _) if b.contains(N.toDouble(p)) => p |
There was a problem hiding this comment.
The same argument about translating this to a simple if holds here as well.
|
Looking great. Will merge a little later today |
|
After some more thought, we can do better :) I'll make some notes of what I'm thinking - a lot of the functions are transformations that are not really involved with Lenses. |
|
@KyleErwin Please have a look at #283, if you're happy with that approach, could you close this PR? |
Added a few bchms that I did in a project. Some of these were given by prof, and others I found in reading.
There are few others that I did that involved in re-initialization with randomness that I just want to rework to be neater.