Skip to content

Commit

Permalink
0.99.1 Add description of algorithms in Scaladoc, resolve issues with…
Browse files Browse the repository at this point in the history
… shadowing types and variables..... see README.ME/latest release for complete information
  • Loading branch information
prnicolas committed Dec 27, 2015
1 parent 184736d commit 43a76d7
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 72 deletions.
23 changes: 11 additions & 12 deletions src/main/scala/org/scalaml/ga/Chromosome.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* concepts and algorithms presented in "Scala for Machine Learning".
* ISBN: 978-1-783355-874-2 Packt Publishing.
*
* Version 0.99
* Version 0.99.1
*/
package org.scalaml.ga

Expand Down Expand Up @@ -43,7 +43,7 @@ import Gene._, Chromosome._
*/
@throws(classOf[IllegalArgumentException])
final class Chromosome[T <: Gene](val code: List[T]) {
require(!code.isEmpty, "Chromosome Cannot create a chromosome from undefined genes")
require( code.nonEmpty, "Chromosome Cannot create a chromosome from undefined genes")
var cost: Double = COST_FACTOR*(1.0 + Random.nextDouble)


Expand All @@ -57,7 +57,7 @@ final class Chromosome[T <: Gene](val code: List[T]) {
* The cross over operation generates two off springs from the two original parents.
* The off-springs are added to the current population along with the parents.
* @param that other parent chromosome
* @param gIdx Genetic index for the cross-over.
* @param indices Genetic index for the cross-over.
* @throws IllegalArgumentException if the other chromosome is undefined, or have a
* different size or if the cross-over factor is out of range.
* @return the pair of offspring chromosomes
Expand All @@ -67,7 +67,7 @@ final class Chromosome[T <: Gene](val code: List[T]) {
require(!that.isEmpty,
"Chromosome.+- Cannot cross-over chromosome with an undefined parent")
require(this.size == that.size,
s"Chromosome.+- Chromosomes ${size} and that ${that.size} have different size")
s"Chromosome.+- Chromosomes $size and that ${that.size} have different size")

// First use the global index (module the number of gene
val xoverIdx = indices.chOpIdx
Expand All @@ -85,7 +85,7 @@ final class Chromosome[T <: Gene](val code: List[T]) {
/**
* Mutation operator that flip a gene selected through a mutation index.
* The mutated gene is added to the population (gene pool).
* @param gIdx Genetic index
* @param indices Genetic index
* @throws IllegalArgumentException if mutation coefficient, mu is out of range
* @return A new mutated chromosome
*/
Expand All @@ -94,7 +94,7 @@ final class Chromosome[T <: Gene](val code: List[T]) {
val mutated = code(indices.chOpIdx) ^ indices

// Flip the bit at index 'gIdx.chOpIdx,
val xs = Range(0, code.size).map(i =>
val xs = code.indices.map(i =>
if(i == indices.chOpIdx) mutated.asInstanceOf[T] else code(i)
).toList
Chromosome[T](xs)
Expand All @@ -104,7 +104,7 @@ final class Chromosome[T <: Gene](val code: List[T]) {
/**
* Normalize the fitness of this chromosome with a factor. This
* operation is required by the selection algorithm.
* @param normalizedFactor normalization factor
* @param normalizeFactor normalization factor
* @throws IllegalArgumentException if the normalization factor is less than EPS
*/
@throws(classOf[IllegalArgumentException])
Expand Down Expand Up @@ -143,17 +143,16 @@ final class Chromosome[T <: Gene](val code: List[T]) {
* Stringize the genetic code of this chromosome
* @return Genetic code {0, 1} for this chromosome
*/
override def toString: String = String.valueOf(code.toString)
override def toString: String = String.valueOf(code.toString())


/**
* Symbolic representation of the chromosome as a sequence of symbolic representation
* of the genes it contains
* @param comment Optional comment for the symbolic representation
* @return sequence of symbolic representation of the genes of this chromosomes
*/
final def symbolic: String =
s"${code.map( _.symbolic).mkString(" ")} cost= $cost fitness: ${fitness}"
s"${code.map( _.symbolic).mkString(" ")} cost= $cost fitness: $fitness"

/*
* Auxiliary method to splice this chromosome with another
Expand Down Expand Up @@ -195,14 +194,14 @@ object Chromosome {
*/
@throws(classOf[IllegalArgumentException])
def apply[T <: Gene](predicates: List[T], encode: T => Gene): Chromosome[T] = {
require( !predicates.isEmpty,
require( predicates.nonEmpty,
"Chromosome.apply List of predicates is undefined")

// Create a chromosome with a single gene for a single predicate
// or a list of gene for multiple predicate.
// A gene is actually generated by encoding the predicate
new Chromosome[T](if(predicates.size == 1)
List[T](encode(predicates(0)).asInstanceOf[T])
List[T](encode(predicates.head).asInstanceOf[T])
else
predicates./:(List[T]()) ((xs, t) => encode(t).asInstanceOf[T] :: xs))
}
Expand Down
14 changes: 7 additions & 7 deletions src/main/scala/org/scalaml/ga/GAConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* concepts and algorithms presented in "Scala for Machine Learning".
* ISBN: 978-1-783355-874-2 Packt Publishing.
*
* Version 0.99
* Version 0.99.1
*/
package org.scalaml.ga

Expand All @@ -24,7 +24,7 @@ import org.scalaml.core.Design.Config
* Configuration class that defines the key parameters for the execution of the
* genetic algorithm solver (or optimizer). The list of configuration parameters include
* mutation, cross-over ratio, maximum number of optimization cycles (or epochs) and a soft limiting
* function to constaint the maximum size of the population of chromosomes at each cyles
* function to constaint the maximum size of the population of chromosomes at each cycles
* (or epochs)
*
* {{{
Expand All @@ -45,7 +45,7 @@ import org.scalaml.core.Design.Config
*
* @author Patrick Nicolas
* @since 0.97 August 28, 2013
* @version 0.98.2
* @version 0.99
* @see Scala for Machine Learning Chapter 10 ''Genetic Algorithm'' / Implementation / GA
* configuration
*/
Expand All @@ -61,7 +61,6 @@ final class GAConfig(

/**
* re-compute the mutation factor using an attenuator
* @param cycle number of the current cycle
* @return soft limit computed for this cycle
*/
@throws(classOf[IllegalArgumentException])
Expand Down Expand Up @@ -94,7 +93,7 @@ object GAConfig {
* Default constructor for the GAConfig class
* @param xover Value of the cross-over parameter, in the range [0.0, 1.0] used to compute
* the index of bit string representation of the chromosome for cross-over
* @param mutate Value in the range [0.0, 1.0] used to compute the index of the bit or
* @param mu Value in the range [0.0, 1.0] used to compute the index of the bit or
* individual to be mutate in each chromosome.
* @param maxCycles Maximum number of iterations allowed by the genetic solver
* (reproduction cycles).
Expand All @@ -104,19 +103,20 @@ object GAConfig {
def apply(xover: Double, mu: Double, maxCycles: Int, softLimit: Int =>Double): GAConfig =
new GAConfig(xover, mu, maxCycles, softLimit)

private val DEFAULT_SOFTLIMIT = (n : Int) => -0.01*n + 1.001

/**
* Constructor for the GAConfig class with a default soft limit defined as
* {{{
* f(n) = 1.001 -0.01.n.
* }}}
* @param xover Value of the cross-over parameter, in the range [0.0, 1.0] used to
* compute the index of bit string representation of the chromosome for cross-over
* @param mutate Value in the range [0.0, 1.0] used to compute the index of the bit or
* @param mu Value in the range [0.0, 1.0] used to compute the index of the bit or
* individual to be mutate in each chromosome.
* @param maxCycles Maximum number of iterations allowed by the genetic solver
* (reproduction cycles).
*/
private val DEFAULT_SOFTLIMIT = (n : Int) => -0.01*n + 1.001
def apply(xover: Double, mu: Double, maxCycles: Int): GAConfig =
new GAConfig(xover, mu, maxCycles, DEFAULT_SOFTLIMIT)

Expand Down
13 changes: 6 additions & 7 deletions src/main/scala/org/scalaml/ga/GASolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* concepts and algorithms presented in "Scala for Machine Learning".
* ISBN: 978-1-783355-874-2 Packt Publishing.
*
* Version 0.99
* Version 0.99.1
*/
package org.scalaml.ga

Expand All @@ -36,10 +36,10 @@ import Chromosome._
* class has only one public method search.
* @tparam T Type of the gene (inherited from '''Gene''')
* @constructor Create a generic GA-based solver.
* @param conf Configuration parameters for the GA algorithm. The configuration is used as
* @param config Configuration parameters for the GA algorithm. The configuration is used as
* a model for the explicit data transformation.
* @param score Scoring method for the chromosomes of this population
* @param monitor optional method to monitor the state and size of the population during
* @param _monitor optional method to monitor the state and size of the population during
* reproduction.
*
* @author Patrick Nicolas
Expand Down Expand Up @@ -68,7 +68,7 @@ final protected class GASolver[T <: Gene](
* Method to resolve any optimization problem using a function to generate
* a population of Chromosomes, instead an existing initialized population
* @param initialize Function to generate the chromosomes of a population
* @throws IllegalArgumenException If the initialization or chromosome generation
* @throws IllegalArgumentException If the initialization or chromosome generation
* function is undefined
*/
def |>(initialize: () => Population[T]): Try[Population[T]] = this.|> (initialize())
Expand All @@ -87,9 +87,9 @@ final protected class GASolver[T <: Gene](
* containing the fittest chromosomes as output.
*/
override def |> : PartialFunction[U, Try[V]] = {
case population: U if(population.size > 1 && isReady) => {
case population: U if population.size > 1 && isReady =>

start
start()
// Create a reproduction cycle manager with a scoring function
val reproduction = Reproduction[T](score)

Expand All @@ -107,7 +107,6 @@ final protected class GASolver[T <: Gene](
// The population is returned no matter what..
population.select(score, 1.0)
Try(population)
}
}
}

Expand Down
33 changes: 17 additions & 16 deletions src/main/scala/org/scalaml/ga/Gene.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
* concepts and algorithms presented in "Scala for Machine Learning".
* ISBN: 978-1-783355-874-2 Packt Publishing.
*
* Version 0.99
* Version 0.99.1
*/
package org.scalaml.ga

import java.util
import java.util.BitSet
import scala.annotation.implicitNotFound

Expand Down Expand Up @@ -91,17 +92,16 @@ case class Quantization(toInt: Double => Int, toDouble: Int => Double) {
* (i.e. IF (RSI > 0.8 THEN Stock over-bought ). The gene has a fixed size
* of bits with in this case, two bits allocated to the operator and
* 32 bits allocated to the value. The floating point value(min, max) is
* digitized as integer [0, 2^32-1]. The discretization function is provided
* digitized as integer [0, 2&#94;32-1]. The discretization function is provided
* implicitly. The bits are implemented by the Java BitSet class.
* @constructor Create a gene instance.
* @throws IllegalArgumentException if operator or id is undefined
* @throws ImplicitNotFoundException if the conversion from double to integer (digitize)
* is not provided
* @param id Identifier for the Gene
* @param target Target or threshold value.It is a floating point value to be digitized
* as integer
* @param op Symbolic operator associated to this gene
* @param discr implicit discretization function from Floating point value to integer.
* @param quant implicit discretization function from Floating point value to integer.
*
* @author Patrick Nicolas
* @since August 28, 2013
Expand All @@ -124,8 +124,8 @@ class Gene(
lazy val bits = apply(target, op)


def apply(value: Double, operator: Operator): BitSet = {
val bitset = new BitSet(encoding.length)
def apply(value: Double, operator: Operator): util.BitSet = {
val bitset = new java.util.BitSet(encoding.length)
// Encode the operator
encoding.rOp foreach(i => if( ((operator.id>>i) & 0x01) == 0x01) bitset.set(i))

Expand All @@ -134,7 +134,7 @@ class Gene(
bitset
}

def unapply(bitSet: BitSet): (Double, Operator) =
def unapply(bitSet: util.BitSet): (Double, Operator) =
(quant.toDouble(convert(encoding.rValue, bits)), op(convert(encoding.rOp, bits)))


Expand Down Expand Up @@ -171,7 +171,7 @@ class Gene(
/**
* Implements the cross-over operator between this gene and another
* parent gene.
* @param gIdx Genetic Index for this gene
* @param indices Genetic Index for this gene
* @param that other gene used in the cross-over
* @return A single Gene as cross-over of two parents.
*/
Expand All @@ -196,15 +196,15 @@ class Gene(

/**
* Implements the mutation operator on this gene
* @param gIdx genetic index for the cross-over and mutation of this gene
* @param indices genetic index for the cross-over and mutation of this gene
* @return A mutated gene
*/
def ^ (indices: GeneticIndices): Gene = ^ (indices.geneOpIdx)


/**
* Implements the mutation operator on this gene
* @param index index of the bit to mutate (0 < idx < gene.size)
* @param idx index of the bit to mutate (0 < idx < gene.size)
* @return A mutated gene
*/
def ^ (idx: Int): Gene = {
Expand All @@ -227,7 +227,7 @@ class Gene(
* Textual description of the genetic representation of this gene
*/
override def toString: String =
Range(0, bits.size).map(n => if( bits.get(n) == true) "1" else "0").mkString("")
Range(0, bits.size).map(n => if( bits.get(n)) "1" else "0").mkString("")
}


Expand All @@ -247,7 +247,8 @@ object Gene {
* @param id Identifier for the Gene
* @param target Target or threshold value.It is a floating point value to be digitized as integer
* @param op Symbolic operator associated to this gene
* @param discr implicit quantizationfunction from Floating point value to integer.
* @param quant implicit quantization function from Floating point value to integer.
* @param encoding implicit encoding function for the gene
*/
def apply(id: String, target: Double, op: Operator)
(implicit quant: Quantization, encoding: Encoding): Gene =
Expand All @@ -268,8 +269,8 @@ object Gene {
* @param bits Bitset of this gene
* @return duplicate genetic code
*/
protected def cloneBits(bits: BitSet): BitSet =
Range(0, bits.length)./:(new BitSet)((enc, n) => {
protected def cloneBits(bits: util.BitSet): util.BitSet =
Range(0, bits.length)./:(new util.BitSet)((enc, n) => {
if( bits.get(n))
enc.set(n)
enc
Expand All @@ -278,8 +279,8 @@ object Gene {
/*
* Convert a range of bits within a bit into an integer
*/
private def convert(r: Range, bits: BitSet): Int =
r./:(0)((v,i) =>v + (if(bits.get(i)) (1<<i) else 0))
private def convert(r: Range, bits: util.BitSet): Int =
r./:(0)((v,i) =>v + (if(bits.get(i)) 1<<i else 0))
}

// ------------------------------------------- EOF -------------------------------------------------
Loading

0 comments on commit 43a76d7

Please sign in to comment.