Skip to content

Boundary Constraint Handling Mechanisms #274

Closed
KyleErwin wants to merge 13 commits intociren:masterfrom
KyleErwin:BCHMs
Closed

Boundary Constraint Handling Mechanisms #274
KyleErwin wants to merge 13 commits intociren:masterfrom
KyleErwin:BCHMs

Conversation

@KyleErwin
Copy link
Copy Markdown
Contributor

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.

@gpampara
Copy link
Copy Markdown
Member

Is there a reason why the functions are reevaluating the entity? Additionally, this need not be restricted to Particle, the implicit will ensure that there is the needed state, so it should just be any Entity

Copy link
Copy Markdown
Member

@gpampara gpampara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated
if (b) updatePBest(p) else Step.point(p)
}

def clamping[S](particle: Particle[S, Double])(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated
}

def initToPBAndZeroedVelocity[S](particle: Particle[S, Double])(
implicit M: HasMemory[S, Double], V: HasVelocity[S, Double]): Step[Double, Particle[S, Double]] = {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated
val newVelocity = updated.map(t => t._2)

for {
v <- PSO.updateVelocity(particle, Position.apply(newVelocity, particle.pos.boundary))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really use a Lens to do this update instead of recreating the position

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated
} yield u
}

def initToGB[S](particle: Particle[S, Double], gBest: Position[Double])(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see if we can generalize this to only need an Order, instead of using Double

@KyleErwin
Copy link
Copy Markdown
Contributor Author

Okay cool. I'll change it to entity.
The reason they are reevaluated was because a particle's position and/or velocity are being modified. And when they are modified their fitness values become invalid. I was using a Gbest pso, and these bchms were placed at end of the my pso for step compression. Without the eval step there werent any valid fitness values to be used in the next iteration. In hindsight I perhaps should have placed the bchm before the eval step to avoid this reevaluating thing..

@KyleErwin
Copy link
Copy Markdown
Contributor Author

@gpampara Ive made the code more generic and simpler. Let me know what you think

Copy link
Copy Markdown
Member

@gpampara gpampara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread pso/src/main/scala/cilib/pso/PSO.scala Outdated
object PSO {
import Lenses._

trait LowPriorityFlatten extends Poly1 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be removed.

@gpampara
Copy link
Copy Markdown
Member

gpampara commented Apr 4, 2018

@KyleErwin Please run the code through the scalafmt formater. Can just run scalafmt from sbt.

@KyleErwin
Copy link
Copy Markdown
Contributor Author

@gpampara formatted the code

Comment thread core/src/main/scala/cilib/Entity.scala Outdated
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@KyleErwin
Copy link
Copy Markdown
Contributor Author

@gpampara I think I have removed all partial functions. In the partial cases it was simpler to convert them to if-else blocks

Copy link
Copy Markdown
Member

@gpampara gpampara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread core/src/main/scala/cilib/Entity.scala Outdated
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) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ....

Comment thread core/src/main/scala/cilib/Entity.scala Outdated
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same argument about translating this to a simple if holds here as well.

@gpampara
Copy link
Copy Markdown
Member

gpampara commented Apr 5, 2018

Looking great. Will merge a little later today

@gpampara
Copy link
Copy Markdown
Member

gpampara commented Apr 6, 2018

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.

@gpampara
Copy link
Copy Markdown
Member

@KyleErwin Please have a look at #283, if you're happy with that approach, could you close this PR?

@KyleErwin KyleErwin closed this May 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants