ciren / cilib

Typesafe, purely functional Computational Intelligence
https://cilib.net
Apache License 2.0
124 stars 101 forks source link

A bounded/unbounded archive implementation #293

Closed KyleErwin closed 4 years ago

KyleErwin commented 6 years ago

An archive implementation inspired by @CianSteenkamp96 and my research on the multi guided PSO. The archive can either be Empty or NonEmpty.

final case class Empty[A: Order, B] private[cilib] (b: Bound) extends Archive[A, B]
final case class NonEmpty[A: Order, B] private[cilib] (m: ==>>[A, B], b: Bound)

Both implementations take in some bound type. The bound type is used to (possibly) limit the capacity of the archive.

sealed trait Bound
final case class Bounded (limit: Int Refined Positive) extends Bound
final case class Unbounded () extends Bound

NonEmpty uses a scalaz's ==>> in order to store the keys and values.

KyleErwin commented 6 years ago

Hey @gpampara, I am working on the archive. I think I have addressed some of the change requests. However if you could please explain what you meant by "particularly there needs to be some property tests to make sure the required invariant conditions are defined". Thanks

gpampara commented 6 years ago

Right now the archive implementation doesn't do much more than provide a bounded/unbouded data structure to the user. Fundamentally, a condition function needs to be checked, such as dominance, to determine if the item should actually be inserted / maintained in the structure (potentially removing the dominated solutions). This condition needs to be provided to the archive by the user.

KyleErwin commented 6 years ago

@CianSteenkamp96 I can make the changes to the archive structure to incorporate the dominance function on creation if you like?

CianSteenkamp96 commented 6 years ago

@KyleErwin that would be great thanks.

CianSteenkamp96 commented 6 years ago

An archive implementation inspired by @KyleErwin and my own research on the multi-guided PSO proposed by Dr Christiaan Scheepers.

The archive can either be unbounded (unbounded empty archive), bounded (bounded empty archive), boundedNonEmpty, or unboundedNonEmpty:

private final case class Empty[A](b: ArchiveBound, insertPolicy: (A, A) => Boolean) extends Archive[A] 
private final case class NonEmpty[A](l: List[A], b: ArchiveBound, insertPolicy: (A, A) => Boolean) extends Archive[A] 
def bounded[A](limit: Int Refined Positive, insertPolicy: (A, A) => Boolean, deletePolicy: List[A] => A): Archive[A] def unbounded[A](insertPolicy: (A, A) => Boolean): Archive[A] 
def boundedNonEmpty[A](seeds: NonEmptyList[A], limit: Int Refined Positive, insertPolicy: (A, A) => Boolean, deletePolicy: List[A] => A): Archive[A] 
def unboundedNonEmpty[A](seeds: NonEmptyList[A], insertPolicy: (A, A) => Boolean): Archive[A] 

All implementations require some ArchiveBound type and an insert policy (determining whether a solution is "good" enough to be inserted into the Archive or not). The ArchiveBound type is used to (possibly) limit the capacity of the archive:

sealed trait ArchiveBound final case class Bounded[A](limit: Int Refined Positive, deletePolicy: List[A] => A) extends ArchiveBound final case class Unbounded() extends ArchiveBound

The NonEmpty Archive also accepts a list of "seed" values/solutions to be inserted into the Archive upon creation of the Archive.

The bounded and boundedNonEmpty Archives, in addition, accepts a delete policy which chooses a solution to be removed from the Archive once the Archive has reached max capacity.

The Archive uses a List[A] as the underlying data structure to store solutions inserted into the Archive.