Implementación cambio de moneda con la librería JGAP
1
Implementación del problema de cambio de moneda usando la librería JGAP Paredes, Jose; Sipra, Teddy; Vásquez, Danny y Velásquez, Hemerson.
[email protected],
[email protected],
[email protected],
[email protected]
Universidad Nacional de Trujillo Escuela de Informática
Resumen. El presente artículo muestra la implementación de un algoritmo genético con la librería JGAP para el problema de cambio de moneda. Los datos usados para la aplicación del algoritmo genético pertenecen a un problema de la vida real. Este problema está relacionado con las monedas peruanas. En este problema intervienes monedas desde 1 céntimo hasta 5 soles y billetes de 10 soles a 200 soles.
Índice de Términos Algoritmo, implementación, aplicación, librería.
aleatorios (mutaciones). Así surgen de forma natural más características que a su vez son puestas a prueba y permiten a sus portadores sobrevivir y reproducirse si son las más adecuadas para el ambiente que les rodea. JGAP tiene clases e interfaces para representar: Genes (Gene), cromosomas (Chromosome), individuos (IChromosome), la población (Genotype), la función de ajuste (FitnessFunction) y operadores genéticos. En un sistema monetario determinado existen N monedas de diferente valor v1, v2, . . ., vN ∈ N. Se supone que no hay límite en el número de monedas disponibles de cada valor. Se desea obtener el número mínimo de monedas que son precisas para devolver una cierta cantidad. Debido a lo anterior, para buscar una solución más efectiva del problema de cambio de moneda es necesario la utilización de la librería JGAP.
I. INTRODUCCIÓN
II. DEFINICIÓN Y ANÁLISIS DEL PROBLEMA
JGAP son las siglas de Java Genetic Algortihms Package (paquetes de algoritmos genéticos para java). Es un componente de programación de algoritmos genéticos que se utiliza como un framework. Los algoritmos genéticos se basan en la teoría de la evolución de Charles Darwin. Se tiene una población, donde cada individuo posee diferentes características. Esas características se muestran favorables o no frente a un método de selección al que se enfrentan todos los individuos. Así se van identificando los que poseen las mejores características. Las características de los individuos están dadas por sus cromosomas. Un cromosoma es un conjunto de genes. Cada gen es responsable de indicar el tipo de una sola característica del individuo. El valor que toma el gen se llama alelo. En la biología, los individuos mejor adaptados al medio donde se encuentran son los que sobreviven. De esa forma se reproducen, dando lugar a una descendencia que hereda sus características ventajosas. También se dan variaciones en los genes por medio de la combinación (reproducción sexual) o por cambios
Dada una cantidad en soles que requieren que se descomponga en la menor cantidad posible de monedas. Por ejemplo, si se tienes 25 soles puede descomponerse de la siguiente forma:
Escuela de Informática 2016
2 billetes de 10 soles 1 Moneda de 5 soles Pero también se puede descomponerse de la siguiente forma: 10 Monedas de 1 sol 5 Monedas de 2 soles 1 Moneda de 5 soles O a su vez: 10 Monedas de 2 soles 5 Monedas de 1 sol Hay muchas formas de descomponer este monto en monedas cada una de ellas es una solución al problema (Cromosoma) y tiene un valor de aptitud asociado, que
Implementación cambio de moneda con la librería JGAP
deberá depender de la cantidad de moneda totales de ese cromosoma. Cuantas menos monedas de necesitan más apta será la solución ya que lo se busca es lograr la menor cantidad de monedas posibles. Cada cromosoma tendrá 13 genes. Los genes en este problema son números enteros que representan la cantidad de monedas de cada tipo: Billete de 200 soles Billete de 100 soles Billete de 50 soles Billete de 20 soles Billete de 10 soles Moneda de 5 soles Moneda de 2 soles Moneda de 1 sol Moneda de 50 céntimos Monedad de 20 céntimos Moneda de 10 céntimos Moneda de 5 céntimos
2 variables(); // ------------------------------------------------------------Configuration conf = new DefaultConfiguration(); conf.setPreservFittestIndividual(true); conf.setKeepPopulationSizeConstant(false); FitnessFunction myFunc = new MinimizingMakeChangeFitnessFunction(a_targetChangeAmount); conf.setFitnessFunction(myFunc); if (a_doMonitor) { // Turn on monitoring/auditing of evolution progress. // -------------------------------------------------m_monitor = new EvolutionMonitor(); conf.setMonitor(m_monitor); } Gene[] sampleGenes = new Gene[13]; sampleGenes[0] = new IntegerGene(conf, 0, 4); // Billete 200 soles sampleGenes[1] = new IntegerGene(conf, 0, 4); // Billete 100 soles sampleGenes[2] = new IntegerGene(conf, 0, 4); // Billete 50 soles
III. IMPLEMENTACIÓN Implementación del Cambio mínimo: package Class;
sampleGenes[3] = new IntegerGene(conf, 0, 4); // Billete 20 soles sampleGenes[4] = new IntegerGene(conf, 0, 5); // Billete 10 soles sampleGenes[5] = new IntegerGene(conf, 0, 5); // Moneda 5 soles sampleGenes[6] = new IntegerGene(conf, 0, 7); // Moneda 2 soles sampleGenes[7] = new IntegerGene(conf, 0, 10); // Moneda 1 sol
import java.io.*; import org.jgap.*; import org.jgap.audit.*; import org.jgap.data.*; import org.jgap.impl.*; import org.jgap.xml.*; import org.w3c.dom.*;
sampleGenes[8] = new IntegerGene(conf, 0, 10); // Moneda 50 centimos sampleGenes[9] = new IntegerGene(conf, 0, 10); // Moneda 20 centimos sampleGenes[10] = new IntegerGene(conf, 0, 10); // Moneda 10 centimos sampleGenes[11] = new IntegerGene(conf, 0, 10); // Moneda 5 centimos sampleGenes[12] = new IntegerGene(conf, 0, 10); // Moneda 1 centimos IChromosome sampleChromosome = new Chromosome(conf, sampleGenes);
public class MinimizingMakeChange {
conf.setSampleChromosome(sampleChromosome); conf.setPopulationSize(80);
private static final int MAX_ALLOWED_EVOLUTIONS = 200; public static EvolutionMonitor m_monitor;
Genotype population;
public static String cromoApto = "", timeEvolucion ="", totalMoneda= ""; public static int sol_200=0;
population = Genotype.randomInitialGenotype(conf);
public static int sol_100=0; public static int sol_50=0; public static int sol_20=0;
long startTime = System.currentTimeMillis(); for (int i = 0; i < MAX_ALLOWED_EVOLUTIONS; i++) { if (!uniqueChromosomes(population.getPopulation())) {
public static int sol_10=0;
throw new RuntimeException("Invalid state in generation " + i);
public static int sol_5=0; }
public static int sol_2=0;
if (m_monitor != null) {
public static int sol_1=0;
population.evolve(m_monitor);
public static int cent_50=0;
} else {
public static int cent_20=0;
population.evolve();
public static int cent_10=0; }
public static int cent_5=0; public static int cent_1=0;
} long endTime = System.currentTimeMillis();
public static void makeChangeForAmount(double a_targetChangeAmount,boolean a_doMonitor) throws Exception {
Escuela de Informática 2016
//System.out.println("Total evolution time: " + (endTime - startTime)
Implementación cambio de moneda con la librería JGAP
3
timeEvolucion+="Tiempo total de evolución: " + (endTime - startTime)+ " ms";
MinimizingMakeChangeFitnessFunction.getTotalNumberOfCoins(bestSolutio nSoFar) + " monedas.";
DataTreeBuilder builder = DataTreeBuilder.getInstance();
}
IDataCreators doc2 = builder.representGenotypeAsDocument(population);
public static void variables(){ sol_200=0;
XMLDocumentBuilder docbuilder = new XMLDocumentBuilder();
sol_100=0;
Document xmlDoc = (Document) docbuilder.buildDocument(doc2);
sol_50=0;
XMLManager.writeFile(xmlDoc, new File("JGAPExample26.xml"));
sol_20=0; sol_10=0;
IChromosome bestSolutionSoFar = population.getFittestChromosome();
sol_5=0; sol_2=0;
sol_200=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(
sol_1=0;
bestSolutionSoFar, 0);
cent_50=0; cent_20=0;
sol_100=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(
cent_10=0;
bestSolutionSoFar, 1);
cent_5=0; cent_1=0;
sol_50=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(b
}
estSolutionSoFar, 2); public static boolean uniqueChromosomes(Population a_pop) { sol_20=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(b
for (int i = 0; i < a_pop.size() - 1; i++) {
estSolutionSoFar, 3);
IChromosome c = a_pop.getChromosome(i); for (int j = i + 1; j < a_pop.size(); j++) {
sol_10=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(b
IChromosome c2 = a_pop.getChromosome(j);
estSolutionSoFar, 4);
if (c == c2) {
sol_5=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(be
}
return false; stSolutionSoFar, 5);
} }
sol_2=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(be
return true;
stSolutionSoFar, 6);
} }
sol_1=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(be stSolutionSoFar, 7);
Implementación de la función aptitud del cambio mínimo:
cent_50=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene( bestSolutionSoFar, 8);
package Class;
cent_20=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(
import org.jgap.*;
bestSolutionSoFar, 9); public class MinimizingMakeChangeFitnessFunction extends cent_10=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(
FitnessFunction {
bestSolutionSoFar, 10); private final double m_targetAmount; cent_5=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(b
public static final int MAX_BOUND = 4000;
estSolutionSoFar, 11); public MinimizingMakeChangeFitnessFunction(double a_targetAmount) { if (a_targetAmount < 1 || a_targetAmount >= MAX_BOUND) {
cent_1=MinimizingMakeChangeFitnessFunction.getNumberOfCoinsAtGene(b
throw new IllegalArgumentException("El número debe estar en el
estSolutionSoFar, 12); cromoApto+="\n"+"El cromosoma mas apto encontrado tiene un valor
rango de 1 y " + MAX_BOUND + " soles."); }
de aptitud de: " + bestSolutionSoFar.getFitnessValue();
m_targetAmount = a_targetAmount;
totalMoneda+="\n"+"Para un total de "+ MinimizingMakeChangeFitnessFunction.amountOfChange(bestSolutionSoFar ) + " soles en " +
Escuela de Informática 2016
}
Implementación cambio de moneda con la librería JGAP
4
public double evaluate(IChromosome a_subject) { boolean defaultComparation =
float Moneda100Sol = getNumberOfCoinsAtGene(a_potentialSolution, 1);
a_subject.getConfiguration().getFitnessEvaluator().isFitter(2, 1);
float Moneda50Sol = getNumberOfCoinsAtGene(a_potentialSolution, 2);
double changeAmount = amountOfChange(a_subject);
float Moneda20Sol = getNumberOfCoinsAtGene(a_potentialSolution, 3);
int totalCoins = getTotalNumberOfCoins(a_subject);
float Moneda10Sol = getNumberOfCoinsAtGene(a_potentialSolution, 4);
double changeDifference = Math.abs(m_targetAmount -
float Moneda5Sol = getNumberOfCoinsAtGene(a_potentialSolution, 5);
changeAmount);
float Moneda2Sol = getNumberOfCoinsAtGene(a_potentialSolution, 6);
double fitness;
float Moneda1Sol = getNumberOfCoinsAtGene(a_potentialSolution, 7); float Moneda50Cent = getNumberOfCoinsAtGene(a_potentialSolution,
if (defaultComparation) {
8);
fitness = 0.0d; } else {
float Moneda20Cent = getNumberOfCoinsAtGene(a_potentialSolution, 9);
fitness = MAX_BOUND / 2;
float Moneda10Cent = getNumberOfCoinsAtGene(a_potentialSolution,
}
10);
if (defaultComparation) {
11);
float Moneda5Cent = getNumberOfCoinsAtGene(a_potentialSolution, fitness += changeDifferenceBonus(MAX_BOUND / 2, changeDifference);
float Moneda1Cent = getNumberOfCoinsAtGene(a_potentialSolution, 12);
} else { fitness -= changeDifferenceBonus(MAX_BOUND / 2,
return (Moneda200Sol * 200) + (Moneda100Sol * 100) + (Moneda50Sol * 50) + (Moneda20Sol * 20) + (Moneda10Sol * 10) +
changeDifference);
(Moneda5Sol * 5) + (Moneda2Sol * 2) + (Moneda1Sol * 1) +
}
(Moneda50Cent * (0.5)) + (Moneda20Cent * (0.2)) + (Moneda10Cent * (0.1)) + (Moneda5Cent * (0.05)) + (Moneda1Cent * (0.01));
if (defaultComparation) {
}
fitness -= computeCoinNumberPenalty(MAX_BOUND / 2, totalCoins); } else { fitness += computeCoinNumberPenalty(MAX_BOUND / 2, totalCoins);
public static int getNumberOfCoinsAtGene(IChromosome a_potentialSolution, int a_position) {
}
Integer numCoins = (Integer) a_potentialSolution.getGene(a_position).getAllele();
return Math.max(1.0d, fitness);
return numCoins.intValue();
}
}
protected double changeDifferenceBonus(double a_maxFitness, double a_changeDifference) {
public static int getTotalNumberOfCoins(IChromosome a_potentialsolution) {
if (a_changeDifference == 0) {
int totalCoins = 0;
return a_maxFitness;
int numberOfGenes = a_potentialsolution.size();
} else
for (int i = 0; i < numberOfGenes; i++) {
if (a_changeDifference * a_changeDifference >= a_maxFitness / 2) {
totalCoins += getNumberOfCoinsAtGene(a_potentialsolution, i);
return 0.0d;
}
} else {
return totalCoins;
return a_maxFitness / 2 - a_changeDifference * a_changeDifference; }
} }
} protected double computeCoinNumberPenalty(double a_maxFitness, int a_coins) { if (a_coins == 1) { return 0; } else { return (Math.min(a_maxFitness, a_coins * a_coins)); } } public static double amountOfChange(IChromosome a_potentialSolution) { float Moneda200Sol = getNumberOfCoinsAtGene(a_potentialSolution, 0);
Escuela de Informática 2016
IV. RESULTADOS COMPUTACIONALES La siguiente tabla S1 muestra algunos de los resultados obtenidos de las pruebas ejecutadas, con datos ingresados aleatoriamente.
Implementación cambio de moneda con la librería JGAP
Tabla S1. Evaluación de Resultados
Cantidad
Monedas
200
1 billete de 100 y 2 billetes de 50. 2 billetes de 10, 2 monedas de 2, 1 moneda de 1 y 2 monedas de 0.20 céntimos. 1 billete de 100 y 3 monedas de 1. 2 billetes de 50, 2 billetes de 20, 1 monedas de 0.50, 1 moneda de 0.20 y 1 moneda 0.5.
25.4 103 140.85
V. CONCLUSIONES Los problemas resueltos con algoritmos genéticos buscan la solución más óptima, especialmente al tener muchas soluciones posibles para dicho problema. Por tanto, este estudio considera el problema de cambio de moneda sea resuelto con algoritmos genéticos, apoyados por la librería JGAP, que funciona como un framework a la hora de programar esta clase de algoritmos. ANEXO Resultado programa:
REFERENCIAS [1] Universidad del País Vasco (2010) Algoritmos genéticos. Recuperado el 21 de julio del 2016, del sitio web de Estructura Digital: http://www.sc.ehu.es/ccwbayes/docencia/mmcc/d ocs/temageneticos.pdf [2] Y. del Cisne (2011) Algoritmos Genéticos JGAP. Recuperado el 21 de julio del 2016, del sitio web de Estructura Digital: http://documents.mx/documents/manual-jgap-yalgoritmos-geneticosdocx.html
Escuela de Informática 2016
5
[3] A. Valdez (2012) Librería JGAP. Recuperado el 21 de julio del 2016, del sitio web de Estructura Digital: https://betovaldez.files.wordpress.com/2012/06/j gap.pdf [4] Cultura Científica (2014) El problema del cambio de moneda. Recuperado el 21 de julio del 2016, del sitio web de Estructura Digital: http://culturacientifica.com/2015/07/01/elproblema-del-cambio-de-moneda/