Documente Academic
Documente Profesional
Documente Cultură
Introducci
on
1. Resumen
2. Palabras Clave
3. Introducci
on teorica
3.1. Splines c
ubicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Optimizaci
on combinatoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
3
II
Desarrollo
1. Interpolaci
on y extrapolaci
on
2. Intercepci
on de trayectorias
2.1. Algoritmo Greedy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2. Algoritmo genetico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3. Implementaci
on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
5
5
3. Experimentos
III
Resultados
1. Prueba 1
2. Prueba 2
3. Prueba 3
4. Prueba 4
10
IV
Discusi
on
11
11
11
12
Conclusi
on
1. Sobre el trabajo
12
2. Extensiones al trabajo
12
VI
13
VII
Ap
endice A
Ap
endice B
15
1. Spline.h
15
2. Spline.cpp
15
3. Punto.h
20
4. Punto.cpp
21
5. PosicionBomba.h
22
6. PosicionBomba.cpp
23
7. Misil.h
23
8. Misil.cpp
24
9. Circulo.h
24
10.Circulo.cpp
24
11.EscudoMisiles.h
25
12.EscudoMisiles.cpp
26
28
14.EscudoMisilesBruto.cpp
29
15.Genetico.py
32
VIII
37
Referencias
Parte I
Introducci
on
1.
Resumen
Se implement
o un mecanismo de predicci
on de trayectorias de cuerpos utilizando splines c
ubicos naturales
a partir de lecturas equiparables a las obtenidas por un radar. A continuacion se elaboraron estrategias para,
a partir de dichas trayectorias, interceptar la mayor cantidad posible de ellas utilizando impactos de bomba
en ubicaciones e instantes precisos, utilizando algoritmos greedy y geneticos.
2.
Palabras Clave
Extrapolaci
on con splines c
ubicos
Algoritmo Greedy
Algoritmo Genetico
Optimizaci
on
3.
3.1.
Introducci
on teorica
Splines c
ubicos
3.2.
Optimizaci
on combinatoria
La optimizaci
on combinatoria explora el (usualmente muy grande) conjunto de posibles soluciones a un
problema de optimizaci
on discreto y utiliza tecnicas diversas para mejorar la performance respecto de una
b
usqueda exhaustiva. Estas tecnicas pueden incluir la restriccion del espacio de posibilidades o la b
usqueda
inteligente dentro del mismo.
En particular nuestro problema de optimizacion tiene un conjunto de candidatos del orden de:
n
k
con k la cantidad de bombas a ubicar y n un numero del orden de 109 (correspondiente a la discretizacion
empleada para el espacio de soluciones).
Por tanto, resulta prohibitivo resolver el problema mediante fuerza bruta y recurrimos a algoritmos mas
eficientes que se detallar
an en la secci
on correspondiente del informe.
Parte II
Desarrollo
1.
Interpolaci
on y extrapolaci
on
El objetivo del trabajo es interceptar, mediante impactos de bomba, las trayectorias de misiles que se
aproximan a un planeta en base a lecturas de radar que indican la posicion de los mismos en algunos
instantes dados. Para ello se realiz
o una interpolacion de su trayectoria mediante splines c
ubicos naturales y
se extrapolo su posici
on fuera de los puntos predichos.
Para la realizaci
on del algoritmo de interpolacion por splines c
ubicos naturales se reprodujo el algoritmo
de referencia de (Burden, 1991) sobre una clase de representacion en C++, a la que se a
nadio una funcion de
evaluacion pertinente. Dicha funci
on permite calcular los valores predichos por el polinomio interpolante en
puntos distintos a los provistos para interpolar, y tanto dentro como fuera del rango determinado por estos.
Los puntos interpolados son almacenados en una lista enlazada ya que solo son accedidos secuencialmente
y se facilita el pasaje del par
ametro (ya que no hay que proporcionar el largo de la lista), y los coeficientes de
cada polinomio c
ubico se almacenan en arreglos ya que deben ser accedidos de forma relativamente arbitraria,
y por tanto una secuencia resultara en evaluaciones mas lentas del polinomio.
2.
Intercepci
on de trayectorias
2.1.
Algoritmo Greedy
El primero de los algoritmos propuestos utiliza la metaheurstica conocida como greedyness o codicia. Los
algoritmos de este tipo se caracterizan por el siguiente comportamiento: con el fin de maximizar la aptitud
de una combinaci
on dada de elementos, se busca maximizar la aptitud de uno solo de ellos y se reproduce
este mecanismo hasta obtener una combinacion del largo necesario.
Por ejemplo, si el problema es el de obtener una determinada suma de dinero en la menor cantidad posible
de monedas, un mecanismo greedy para resolver este problema consiste en tomar siempre la moneda de
mayor valor posible que entra en la suma total, y reproducir el procedimiento con el importe restante. As,
para obtener una combinaci
on de monedas que sumen 33 centavos, se toma una de 25 centavos (restan 8
centavos), a continuaci
on una de 5 centavos (restan 3) y finalmente 3 de un centavo. En particular para este
problema la soluci
on propuesta por el algoritmo greedy es optima, pero esto se debe a las caractersticas
inherentes de este ejemplo.
Para la optimizaci
on de ubicaci
on de las bombas en tiempo y espacio, la heurstica utilizada fue simplemente tomar la ubicaci
on espacial y temporal de la bomba que mas misiles intercepta. Para ello se recorren
los tiempos discretizados en busca de este m
aximo. A continuacion se reproduce el mecanismo en los tiempos
posteriores al elegido, y limitando la b
usqueda a los misiles que no fueron eliminados por la bomba anterior.
Ademas, y para acelerar la b
usqueda, solo se recorren los puntos tales que una bomba ubicada en ellos
alcanza cuando menos un misil.
Es claro que este mecanismo no produce necesariamente soluciones optimas, pero su ejecucion es rapida y
estimamos que provee una buena aproximaci
on a la solucion. Por otra parte, al ser un algoritmo determinista
que debe ejecutarse en un tiempo constante, pueden ocurrir dos cosas: que sobre tiempo, y por tanto se
desperdicie la posibilidad de optimizar a
un mas la solucion obtenida, o que no se llegue a completar el
algoritmo en el tiempo especificado, no pudiendo as proveer ninguna solucion. En nuestra implementacion
decidimos solo preocuparnos por la segunda cuestion: si el algoritmo prevee que se quedara sin tiempo para
terminar su ejecuci
on, esta se aborta en el punto en que se encuentra y se terminan de posicionar las demas
bombas utilizando una heurstica a
un m
as sencilla que garantiza u
nicamente que las bombas interceptan
alg
un misil, en lugar de caer en la nada.
2.2.
Algoritmo gen
etico
Los algoritmos geneticos son una forma refinada de comparar candidatos al azar para optimizar un problema. Se comienza con un conjunto de candidatos aleatorios (la poblacion), y se los somete a procesos
comparables a los de la evoluci
on natural de una especie: se cruzan, mutan y envejecen, sobreviviendo solo
los mas aptos dentro del conjunto. La aptitud de un candidato se mide con una funcion definida de forma tal
que deba maximizarse para obtener la soluci
on optima al problema. Ademas se establecen varios parametros
de simulacion, como ser las tasas de mutaci
on y mortalidad, y la forma en que se mutan o cruzan los candidatos para obtener otros nuevos. Estas heursticas resultan en una convergencia que en general conduce a
una buena soluci
on del problema.
En nuestro caso, cada candidato es una secuencia de PosicionesBomba (que se componen de un punto y
un instante), y la funci
on de aptitud eval
ua varios factores: se favorece que el conjunto de posiciones elimine
la mayor cantidad posible de misiles, y que una cierta PosicionBomba elimine un n
umero grande de misiles
(aunque con menor fuerza que el criterio anterior, que es el verdadero determinante de las cualidades de una
solucion). Se penaliza por otra parte que haya bombas desperdiciadas, y que alguna bomba impacte con la
superficie del planeta.
Este procedimiento tiene la ventaja de que al ser iterativo, se puede aprovechar al maximo el tiempo
disponible para realizar los c
alculos. Sin embargo, y por su naturaleza aleatoria, es imposible garantizar las
cualidades de la soluci
on obtenida, a pesar de que un buen conjunto de heursticas de cruza, mutacion y
aptitud dan la pauta de que se obtiene una solucion cuando menos decente en un tiempo razonable. Por lo
tanto, puede ocurrir que en una corrida para una instancia dada del problema se obtenga rapidamente la
solucion optima, mientras que en otra ejecucion subsiguiente no se consiga el resultado deseado.
2.3.
Implementaci
on
Se realizaron prototipos de los algoritmos en Python con la idea de luego portarlos C++. Finalmente
se resolvio portar u
nicamente el algoritmo greedy ya que el algoritmo genetico usaba muchas cualidades
dinamicas del lenguaje y se haca muy complejo de implementar en C++, ademas de que requeria tiempo
del que no disponiamos. Se presentan de todos modos las versiones de los prototipos en Python, que son
perfectamente funcionales, as como el c
odigo en C++. En ambos algoritmos se considero que el tiempo
maximo que le insume a un misil alcanzar el planeta esta acotado. El lmite elegido fue 10, ya que este es el
largo de la simulaci
on realizada por el simulador de referencia. Para modificar este lmite, solo es necesario
alterar el valor de T IEM P O BU SQU EDA en EscudoMisiles.cpp y escudo.py.
3.
Experimentos
Para estudiar el funcionamiento de los algoritmos se realizaron experiencias que pretendan buscar casos
donde los mismos pudieran mostrar un comportamiento no optimo. Asi se busco, por ejemplo, un caso donde
por tomar un valor
optimo localmente, el algoritmo greedy no logra obtener el maximo global, as como
otro donde la soluci
on
optima no sea encontrada por el algoritmo genetico ya que resultaba ser demasiado
sensible a peque
nos cambios de posici
on (el conjunto de soluciones optimas era muy reducido). Para esto se
utilizaron los archivos de prueba provistos por los docentes, asi como tambien otros elaborados por nosotros
mismos y otros grupos. Los resultados de algunas de las simulaciones obtenidas se encuentran en el apartado
de resultados.
Parte III
Resultados
1.
Prueba 1
2.
Prueba 2
3.
Prueba 3
4.
Prueba 4
10
Parte IV
Discusi
on
1.
En la prueba 1 se observa como el algoritmo greedy logra encontrar una solucion optima mientras que
el algoritmo genetico no. Esto se debe a que para lograr contener a todos los misiles del lado izquierdo, el
margen para colocar la bomba es muy peque
no, por lo cual el algoritmo genetico no consigue localizarlo en
los 20 segundos que se le otorgan. En cambio, como en este caso la union de los maximos locales - es decir
interceptar cada vez la mayor cantidad posible de misiles - es una solucion optima, el greedy obtiene un
mejor resultado.
En la prueba 2 ambos algoritmos logran una solucion optima. Esto se debe a que nuevamente la union
de los maximos locales permite encontrar un maximo global, y que a diferencia de la prueba anterior las
bombas tienen un margen m
as amplio para ser colocadas logrando interceptar a todos los misiles, por lo cual
el tiempo del algoritmo genetico resulta suficiente para hallar la solucion optima.
En la prueba 3 se pone de manifiesto como el algoritmo greedy por su condicion eager se inclina por una
solucion no adecuada. En este caso el m
aximo local que toma es el primer cruce de dos misiles, al eliminar
a esos dos misiles se queda con otros dos disjuntos a los que no puede matar con una sola bomba. Si no se
quedara con ese m
aximo local, podra haber logrado interceptar a los 4 misiles como lo hizo el otro algoritmo.
En la prueba 4 ninguno de los dos metodos logra un resultado optimo. El algoritmo greedy no lo hace por
las mismas razones por las que no lo hace en la prueba 3. En cambio el genetico, que antes s lo resolva
correctamente ahora falla tambien. Esto se debe a que en esta prueba el n
umero de misiles es mas grande
por lo cual necesita de m
as iteraciones hasta lograr una mejor solucion. Sin embargo, como el tiempo de
ejecucion es el mismo, no logra encontrarla y devuelve la mejor solucion que encontro, y que no es la mejor
posible.
2.
En general se observ
o que para la mayora de los casos el algoritmo greedy se comporta de forma muy
satisfactoria, eliminando una cantidad m
axima de misiles en un tiempo de calculo muy acotado.
Sin embargo es de destacarse tambien que esto puede deberse fuertemente al modelo utilizado para representar los misiles. Cuando se construye la trayectoria de un misil se hace a partir de puntos en la misma, y
esto introduce la limitaci
on de que solo pueden utilizarse bombas luego de colocada la u
ltima medicion. De
esta forma, el comportamiento de un misil luego de ese momento sigue una funcion c
ubica tradicional, sin
alteraciones mayores, y no se producen grandes cambios en la direccion de un misil, en esta circunstancia
uniforme el algoritmo greedy se comporta particularmente bien (por naturaleza).
En general el algoritmo genetico es inherentemente mas lento que el greedy, por la complejidad adicional
de las operaciones que realiza y porque no fue implementado en C++. Con el lmite de tiempo de 20 segundos
que se le impone, los resultados que se obtienen son en general peores que los del otro algoritmo, aunque en
general ofrece resultados bastante razonables como es esperable.
Por otro lado si observamos el (relativamente sencillo) contraejemplo hallado para la optimalidad de los
resultados del algoritmo greedy, resulta claro que el algoritmo genetico produce una respuesta mejor. A esto
se agrega el hecho de que con m
as tiempo de ejecucion, es probable que el algoritmo genetico hubiera resuelto
correctamente el caso propuesto en la prueba 4.
Como generalizaci
on podra decirse que el algoritmo genetico produce resultados de calidad menor pero
mas parejos, mientras que el algoritmo greedy, al ser mas ingenuo, puede producir resultados muy buenos
tanto como muy malos.
11
Parte V
Conclusi
on
1.
Sobre el trabajo
El problema de optimizaci
on a resolver es altamente complejo dadas las condiciones impuestas sobre el
algoritmo de resoluci
on, tanto en tiempo de ejecucion como de desarrollo. Propusimos dos alternativas que,
en conjunto, consiguen resolver de forma relativamente satisfactoria el problema para instancias peque
nas
del mismo.
2.
Extensiones al trabajo
Las mejoras m
as obvias al trabajo son las de mejorar su eficiencia, ya sea implementando el algoritmo
genetico en C++ y optimizando su comportamiento, como explorando otras alternativas para la resolucion del problema. En particular puede resultar interesante evaluar un algoritmo utilizando programacion
dinamica, aunque por la complejidad del problema puede llegar a resultar prohibitivamente lento. Alternativamente, puede resultar adecuado implementar varias alternativas de resolucion y elegir entre ellas la que
mas apta resulte para una instancia dada, ya que los diferentes algoritmos tienen capacidades distintas frente
a problemas de diferentes caractersticas.
12
Parte VI
Ap
endice A
Laboratorio de M
etodos Num
ericos - Segundo cuatrimestre 2007
Trabajo Pr
actico N
umero 4: Impacto profundo
Introducci
on
Nos encontramos nuevamente en el Centro de Operaciones Logsticas Laterales (C.o.l.l.), en uno de los
momentos mas dram
aticos de la XLII Guerra Intergalactica. El planeta Z-80 esta siendo atacado por un
conjunto de misiles que amenazan su integridad, y nuestra mision consiste en detener este cruel ataque.
Para defender al planeta Z-80 contamos con un n
umero reducido de bombas de destruccion masiva. Estas
bombas son enviadas a un punto del espacio circundante a nuestro planeta, donde se las hace explotar. La
explosion genera una onda expansiva que destruye todos los objetos (y misiles) ubicados a menos de un cierto
radio crtico del centro de la explosi
on.
Nuestros radares nos proporcionan la posicion exacta de los misiles enemigos a intervalos de tiempo
aproximadamente constantes1 . En funci
on de estas mediciones deberemos determinar las trayectorias futuras
de los misiles y, sobre la base de estas estimaciones, deberemos decidir en que lugar y en que momento tenemos
que producir las explosiones de nuestras bombas defensivas, con el objetivo de destruir la mayor cantidad de
misiles enemigos. La supervivencia de nuestro planeta esta en sus manos.
Enunciado
El objetivo del trabajo pr
actico es implementar un programa que lea las mediciones de las posiciones
de los misiles desde un archivo de texto, y que deje en otro archivo el momento y la posicion en la que
debera detonarse cada bomba defensiva, con el objetivo de maximizar la cantidad de misiles enemigos destruidos. Debido a la urgencia que tenemos para activar nuestras defensas, el programa no debera utilizar
mas de 20 sg. de procesamiento total.
El archivo de entrada contiene las posiciones de los misiles enemigos a intervalos de tiempo constantes de
1 sg. Para estimar la trayectoria futura de cada misil se deberan interpolar las mediciones de las posiciones
enemigas con splines parametricos naturales, utilizando la extrapolacion de cada spline hacia el futuro como
una estimacion de la trayectoria correspondiente.
El programa debe tomar por lnea de comandos los nombres del archivo de entrada y del archivo de salida,
de la siguiente forma:
tp4.exe misiles.txt bombas.txt
El archivo con los datos de entrada (llamado misiles.txt en el ejemplo) tiene en la primera lnea la
cantidad n de misiles y la cantidad m de mediciones para cada uno. A continuacion, se incluyen m filas
correspondientes al primer misil, cada una de las cuales contiene las coordenadas x e y de la posicion del
misil en los instantes t = 1, 2, . . . , m sg. (simplificamos el analisis considerando un espacio bidimensional).
Luego de las m lneas correspondientes al primer misil, el archivo contiene m lneas con el mismo formato
correspondientes al segundo misil, etc. Por u
ltimo, el archivo contiene una lnea con la cantidad b de bombas
defensivas, el radio r de la onda expansiva de cada una y el radio R de nuestro planeta, cuyo centro suponemos
ubicado en el origen de coordenadas. Por ejemplo, el siguiente archivo es un ejemplo de datos de entrada
validos:
3 4
1.0
1.1
1.23
1.27
2.5
2.4
2.3
2.15
1 Dominamos
los viajes interplanetarios pero nuestros radares usan la anticuada tecnologa del siglo XXI.
13
1.9
1.8
1.7
1.75
3.5
3.4
3.2
2.9
-2.2
-2.15
-2.12
-2.08
2.3
2.23
2.17
2.11
2 0.7 1.0
Por su parte, el archivo de salida (llamado bombas.txt en el ejemplo) debe tener una lnea por cada bomba,
que contenga el instante de la explosi
on y las coordenadas x e y del centro de la explosion. Es importante
notar que el punto central de cada explosi
on debe tener una distancia al origen de coordenadas de al menos
R + r, para evitar que parte del planeta sea destruido por nuestras mismas bombas defensivas. Por ejemplo,
si b = 2 el siguiente es un ejemplo de archivo de salida:
2.4
1.6
2.15 2.80
-2.04 2.50
El informe debe contener todas las opciones que el grupo haya considerado para determinar los instantes
y posiciones en los que se deben detonar las bombas defensivas.
14
Parte VII
Ap
endice B
1.
Spline.h
#ifndef spline H
#define spline H
#include
#include
#include
#include
#include
<list>
<iostream>
<cstdlib>
<math.h>
<assert.h>
#include Punto.h
#include Circulo.h
using namespace std;
class Spline {
public:
Spline();
Spline(const Spline& otro);
Spline(list<Punto>& puntosDePaso);
Spline();
double evaluar(double x);
void mostrar();
Spline operator=(const Spline &otro);
bool operator!=(Spline otro);
double operator() (double x);
bool operator==(Spline otro);
private:
double** l;
list<Punto> puntos;
void borrar();
void copiar(const Spline &otro);
};
#endif /* Spline H*/
2.
Spline.cpp
#include Spline.h
#include imprimirLista.h
15
Spline :: Spline(){}
void Spline :: mostrar(){
list<Punto> :: iterator p = this->puntos.begin();
Punto xj = (*p);
p++;
Punto xjm1 =(*p);
for(unsigned int i = 0; i < puntos.size()-1; i++){
cout<<Spline entre: <<xj<< <<xjm1<<endl;
cout<<l[i][0]<< ;
cout<< l[i][1]<< ;
cout<< l[i][2]<< ;
cout<< l[i][3]<< ;
cout<<endl;
xj=xjm1;
p++;
cout<<i: <<i<<endl;
if(p != puntos.end())
xjm1=(*p);
}
cout<<endl;
}
16
17
l[0] = 1;
mu[0] = 0;
z[0] = 0;
l[n] = 1;
z[n] = 0;
c[n] = 0;
int j;
for(int i = 1; i < n+1; i++) {
j = n-i;
c[j] = z[j] - mu[j] * c[j+1];
b[j] = (a[j+1] - a[j])/h[j] - (h[j]*(c[j+1] + 2*c[j]))/3.0;
d[j] = (c[j+1] - c[j]) / (3.0 * h[j]);
}
// preparo el vector donde voy a guardar los coeficientes obtenidos
this->l = new double* [n];
for(int i = 0; i < n ; i++) {
this->l[i] = new double[4];
}
// los guardo
for(int i = 0; i < n; i ++) {
this->l[i][0] = a[i];
this->l[i][1] = b[i];
this->l[i][2] = c[i];
this->l[i][3] = d[i];
}
puntos = puntosDePaso;
delete[]
delete[]
delete[]
delete[]
delete[]
delete[]
delete[]
delete[]
delete[]
h;
alfa;
l;
mu;
z;
a;
xs;
b;
c;
18
delete[] d;
}
void Spline :: borrar(){
int largo = puntos.size() - 1;
for(int i=0; i < largo; i++) {
delete[] l[i];
}
delete[] l;
}
Spline :: Spline() {
borrar();
}
19
3.
Punto.h
#ifndef punto H
#define punto H
#include
#include
#include
#include
<list>
<cstdlib>
<math.h>
<iostream>
20
4.
Punto.cpp
#include Punto.h
Punto :: Punto() {
}
Punto :: Punto(double xx, double yy) {
x = xx;
y = yy;
}
list<double> ys;
for(double i = -1*discretizacion; i < discretizacion; i++){
ys.insert(ys.begin(), y + radio*i/discretizacion);
}
list<Punto>* puntos = new list<Punto>;
for(list<double> :: iterator itx = xs.begin(); itx != xs.end(); itx++){
for(list<double> :: iterator ity = ys.begin(); ity != ys.end(); ity++){
puntos->insert(puntos->begin(), Punto((*itx), (*ity)));
}
}
return puntos;
}
double Punto :: maxCoord(){
if (x >= y) {
return x;
}
else {
return y;
}
}
5.
PosicionBomba.h
#ifndef PosBomba H
#define PosBomba H
#include
#include
#include
#include
#include
<list>
<iostream>
<cstdlib>
<math.h>
<assert.h>
#include Spline.h
#include Punto.h
#include Circulo.h
class PosicionBomba {
public:
PosicionBomba();
PosicionBomba(double tiempo, Punto punto);
bool operator<(PosicionBomba otro);
22
Punto punto;
double tiempo;
};
#endif /* PosBomba H*/
6.
PosicionBomba.cpp
#include PosicionBomba.h
PosicionBomba :: PosicionBomba() {}
PosicionBomba ::PosicionBomba(double tiempo, Punto punto) {
this->tiempo = tiempo;
this->punto = punto;
}
bool PosicionBomba :: operator<(PosicionBomba otro) {
return tiempo < otro.tiempo;
}
7.
Misil.h
#ifndef Misil H
#define Misil H
#include
#include
#include
#include
#include
<list>
<iostream>
<cstdlib>
<math.h>
<assert.h>
#include Spline.h
#include Punto.h
#include Circulo.h
class Misil {
public:
Misil();
Misil(Spline splinex, Spline spliney);
Punto posicion(double t);
Spline spx;
Spline spy;
};
#endif /* Misil H*/
23
8.
Misil.cpp
#include Misil.h
Misil :: Misil() {}
Misil :: Misil(Spline splinex, Spline spliney) {
spx = splinex;
spy = spliney;
}
Punto Misil :: posicion(double t) {
return Punto(spx(t), spy(t));
}
9.
Circulo.h
#ifndef Circulo H
#define Circulo H
#include Punto.h
class Circulo {
public:
Circulo();
Circulo(Punto centro, double radio);
double radio;
Punto centro;
bool pertenece(Punto p);
unsigned int cuantosPertenecen(list<Punto> puntos);
friend std::ostream& operator<< (std::ostream&, const Circulo&);
};
#endif /* Circulo H*/
10.
Circulo.cpp
#include Circulo.h
Circulo :: Circulo() {
}
Circulo :: Circulo(Punto p, double r){
centro = p;
radio = r;
}
24
11.
EscudoMisiles.h
#ifndef Escudo H
#define Escudo H
#include
#include
#include
#include
#include
#include
#include
<list>
<iostream>
<cstdlib>
<math.h>
<assert.h>
<string>
<fstream>
#include timer.h
#include
#include
#include
#include
#include
Spline.h
Punto.h
Circulo.h
PosicionBomba.h
Misil.h
#define DELAY INICIAL 0.025 // delay a partir de t0 para tirar la 1ra bomba
#define PASO TIEMPO 0.05
#define TIEMPO MAXIMO CORRIDA 20
using namespace std;
class EscudoAntiMisiles {
public:
EscudoAntiMisiles();
25
EscudoAntiMisiles(string ruta);
void guardar(string ruta);
void mostrar();
int bombas;
int tiempos;
double radioBomba;
double radioTierra;
double tiempoInicial;
double tiempoFinal;
list<Misil> misiles ;
list<PosicionBomba> posicionesBombas;
timer timer total;
private:
double cuandoEntraEnRadio(Misil m, double radio, double t0=0, double paso=PASO TIEMPO);
};
#endif /* Escudo H*/
12.
EscudoMisiles.cpp
#include EscudoMisiles.h
#include imprimirLista.h
#define TIEMPO CRITICO 19.8
#define TIEMPO BUSQUEDA 10
EscudoAntiMisiles :: EscudoAntiMisiles() {}
void EscudoAntiMisiles :: mostrar() {
cout<<Cantidad de bombas: <<bombas<<endl;
cout<<Tiempos: << tiempos<<endl;
cout<<lista de misiles: <<endl;
for(list<Misil> :: iterator m = misiles.begin(); m != misiles.end(); m++) {
cout<<misil:<<endl;
m->spx.mostrar();
m->spy.mostrar();
}
}
EscudoAntiMisiles :: EscudoAntiMisiles(string ruta) {
timer total.start();
cout << Leyendo datos de radar...
cout.flush();
fstream f (ruta.c str());
assert(f.is open());
int mediciones, cantMisiles;
f>>cantMisiles;
f>>mediciones;
26
f.ignore( 1, 0 \n0 );
list<Misil> lista misiles;
for(int m =0; m < cantMisiles; m++) {
list<Punto> puntos x;
list<Punto> puntos y;
for(int t = 1; t < mediciones + 1; t++) {
double x, y;
f>>x;
f>>y;
puntos x.insert(puntos x.end(),Punto(t, x));
puntos y.insert(puntos y.end(),Punto(t, y));
}
f.ignore( 1, 0 \n0 ); //linea vacia
Spline* sx = new Spline(puntos x);
Spline* sy = new Spline(puntos y);
Misil* misi = new Misil(*sx, *sy);
lista misiles.insert(lista misiles.end(),*misi);
delete sx;
delete sy;
delete misi;
puntos x.clear();
puntos y.clear();
}
f>>this->bombas;
double radio tierra, radio bomba;
f>> radio bomba;
f>> radio tierra;
this->tiempos = mediciones;
this->misiles = lista misiles;
this->radioBomba = radio bomba;
this->radioTierra = radio tierra;
this->tiempoInicial = mediciones;
cout << OK!<< endl;
27
13.
#ifndef Bruto H
#define Bruto H
28
#include
#include
#include
#include
#include
<list>
<iostream>
<cstdlib>
<math.h>
<assert.h>
#include
#include
#include
#include
Spline.h
Punto.h
Circulo.h
EscudoMisiles.h
14.
EscudoMisilesBruto.cpp
#include EscudoMisilesBruto.h
#define TIEMPO CRITICO 19.8
void EscudoAntiMisilesBruto :: proponerSolucion() {
if(timer total.elapsed time() >= TIEMPO CRITICO){
cout<<Solucion de emergencia<<endl;
solucionRapida();
return;
}
cout << Optimizando posiciones de las bombas...
cout.flush();
int totalMAtados=0;
list<PosicionBomba> bombas;
double t = this->tiempoInicial + DELAY INICIAL;
for(int i = 0; i < this->bombas; i++) {
Circulo mejor;
double tiempoMejor = 0;
int misilesQueAlcanza = 0;
while(t <= this->tiempoFinal) {
if(timer total.elapsed time() >= TIEMPO CRITICO){
cout<<Solucion de emergencia<<endl;
solucionRapida();
return;
}
if(misiles.empty()) {
29
// toma el circulo que mas misiles alcanza en el instante t, para todos los misiles disponibles
Circulo EscudoAntiMisilesBruto :: mejorCirculo(double t, int& cuantosMata, int discretizacion)
{
list<Punto> puntos;
for(list<Misil> :: iterator m = misiles.begin(); m != misiles.end(); m++) {
puntos.insert(puntos.begin(), m->posicion(t));
}
list<Punto> centrosPosibles;
for(list<Punto> :: iterator p = puntos.begin(); p != puntos.end(); p++) {
list<Punto>* aux = p->puntosLindantes(this->radioBomba, discretizacion);
centrosPosibles.insert(centrosPosibles.begin(), aux->begin(), aux->end());
delete aux;
}
30
list<Circulo> circulos;
for(list<Punto> :: iterator p = centrosPosibles.begin(); p != centrosPosibles.end(); p++)
{
circulos.insert(circulos.begin(), Circulo(*p, radioBomba));
}
Circulo mejor;
if(!circulos.empty()) {
mejor = circulos.front();
} else {
abort();
}
int cuantos = mejor.cuantosPertenecen(puntos);
for(list<Circulo> :: iterator c = circulos.begin(); c != circulos.end(); c++) {
int n = c->cuantosPertenecen(puntos);
Punto p = c->centro;
if(n > cuantos && (p.distancia(Punto(0,0)) > radioBomba+radioTierra)) {
mejor = *c;
cuantos = n ;
}
}
cuantosMata = cuantos;
return mejor;
}
void EscudoAntiMisilesBruto :: solucionRapida(){
for(int i = 0; i <bombas; i++){
Misil mis = misiles.front();
Circulo c(mis.posicion(tiempoInicial+DELAY INICIAL),radioBomba);
list<Misil> aux;
for(list<Misil> :: iterator m = misiles.begin(); m != misiles.end(); m++) {
if(! c.pertenece(m->posicion(tiempoInicial+DELAY INICIAL))) {
aux.insert(aux.begin(),*m);
}
}
PosicionBomba p(tiempoInicial+DELAY INICIAL, mis.posicion(tiempoInicial+DELAY INICIAL));
posicionesBombas.insert(posicionesBombas.begin(), p );
misiles.clear();
for(list<Misil> :: iterator m = aux.begin(); m != aux.end(); m++) {
misiles.insert(misiles.begin(),*m);
}
aux.clear();
}
}
31
15.
Genetico.py
Las clases escudo, misil, posicionBomba, Punto, Circulo que aparecen en el archivo, son iguales a sus
homonimas en C++ salvando las diferencias de sintaxis. Por cuestiones de espacio no se adjunta en este
apendice todo el c
odigo.
#!/usr/bin/python
# -*- coding: iso-8859-1 -*import sys, getopt
import psyco
psyco.full()
from escudo import *
class EscudoAntiMisilesGenetico(EscudoAntiMisiles):
TASA MORTALIDAD = 0.5
TASA MUTACION = 0.3
TAMANIO POBLACION = 40
PASO COORDENADA = 0.1
generacion = 1
poblacion = []
cuantosMueren = int(TAMANIO POBLACION * TASA MORTALIDAD)
cuantosMutan = int(TAMANIO POBLACION * TASA MUTACION)
def posicionAleatoria(self, indiv=[]):
tiempoAleat = random.sample(self.tiemposPosibles,1)[0]
misilAleat = random.sample(self.misiles,1)[0]
puntos = misilAleat.posicion(tiempoAleat).puntosLindantes(self.radioBomba, 10)
lugarAleat = random.sample(puntos, 1)[0]
return PosicionBomba(tiempoAleat,lugarAleat)
def mutar(self, individuo):
random.shuffle(individuo)
for i in range(self.MAXIMAS MUTACIONES):
individuo.pop()
for i in range(self.MAXIMAS MUTACIONES):
individuo.append(self. posicionAleatoria(individuo))
individuo.sort()
def aptitud(self, individuo):
misilesQueHay = self.misiles[:]
misilesQueQuedan = self.misiles[:]
indicesQueFueron = []
borrados = 0
min cuantosMata = len(self.misiles)
32
esHabil = 0
for b in individuo:
cuantosMata = 0
for i in range(len(misilesQueHay)):
if Circulo(b.punto,self.radioBomba).pertenece(misilesQueHay[i].posicion(b.tiempo)):
borrados += 1
cuantosMata += 1
indicesQueFueron.append(i)
misilesQueHay = [misilesQueHay[j] for j in range(len(misilesQueHay)) if not j in
indicesQueFueron]
esHabil += cuantosMata**2
if cuantosMata < min cuantosMata:
min cuantosMata = cuantosMata
indicesQueFueron = []
# penalizo fuertemente las bombas que no golpean nada (a menos que se consiga matar todos los
misiles)
penalidadPorInutil = 0
if borrados != len(self.misiles) and min cuantosMata == 0:
penalidadPorInutil = -30
# penalizo fuertemente las bombas que tocan la tierra
cero = Punto(0,0)
tocanLaTierra = 0
for b in individuo:
if b.punto.distancia(cero) <= self.radioTierra + self.radioBomba:
tocanLaTierra += 1
penalidadPorTocarLaTierra = tocanLaTierra * -50
# favorezco que cada bomba golpee una buena cantidad de misiles en lugar de solo uno
bonusPorGolpearMuchosMisiles = esHabil * 0.1
# favorezco que se elimine la mayor cantidad posibles de misiles
bonusPorEliminarMisiles = -(len(self.misiles) - borrados) * 2
return bonusPorEliminarMisiles + \
bonusPorGolpearMuchosMisiles + \
penalidadPorTocarLaTierra + \
penalidadPorInutil
33
for i in range(5):
aux = random.sample(padre, cuantos padre) + random.sample(madre, cuantos madre)
aux.sort()
if self. aptitud(ind) < self. aptitud(aux) :
ind = aux[:]
return ind
def cmpindividuos(self, a, b):
return cmp(self. aptitud(a), self. aptitud(b))
def avanzarGeneracion(self):
print Generacion %s: % self.generacion,
# mato a los menos aptos
self.poblacion.sort(self. cmpindividuos)
self.poblacion.reverse()
print max(aptitud) = %s % self. aptitud(self.poblacion[0])
for i in range(self.cuantosMueren):
self.poblacion.pop()
# cruzo
hijos = []
for i in range(self.cuantosMueren):
padre, madre = random.sample(self.poblacion, 2)
hijos.append(self. cruzar(padre, madre))
self.poblacion.extend(hijos)
# muto
for i in range(self.cuantosMutan):
self. mutar(self.poblacion[self.TAMANIO POBLACION -1 - i])
self.generacion += 1
def inicializarPoblacion(self):
self.MAXIMAS MUTACIONES = self.bombas
# genero los posibles tiempos
self.tiemposPosibles = []
t = self.tiempoInicial + DELAY INICIAL
while(t <= self.tiempoFinal):
self.tiemposPosibles.append(t)
t += PASO TIEMPO
34
self.poblacion.append(ind)
def proponerSolucion(self):
self. inicializarPoblacion()
machoAlfa = self.poblacion[0]
t = time.time()+ TIEMPO MAXIMO CORRIDA - 1
while (time.time() < t):
f = self. avanzarGeneracion()
self.poblacion.sort(self. cmpindividuos)
self.poblacion.reverse()
machoAlfa = self.poblacion[0]
self.posicionesBombas = self.poblacion[0]
def usage():
print Uso: python genetico.py --input=<archivoDeEntrada> --output=<archivoDeSalida>
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], :, [help, output=, input=])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
input = None
output = None
for o, a in opts:
if o == --help:
usage()
sys.exit()
elif o == --output:
output = a
elif o == --input:
input = a
if output is None or input is None:
print Debe especificar un archivo de entrada y uno de salida!
usage()
sys.exit(1)
#try:
e = EscudoAntiMisilesGenetico(input)
#except:
#
print El archivo de entrada no es correcto!
# sys.exit(1)
e.proponerSolucion()
try:
e.guardar(output)
except:
35
name ==
main()
main
36
Parte VIII
Referencias
Bibliografa
[1] Kincaid, David - Cheney, Ward An
alisis numerico : las matematicas del calculo cientfico Wilmington,
DE : Addison Wesley Iberoamericana, c1994
[2] Richard L. Burden, J. Douglas Faires Analisis Numerico Grupo Editorial Iberoamerica
[3] http://es.wikipedia.org/wiki/Spline
http://en.wikipedia.org/wiki/Greedy_algorithm
http://en.wikipedia.org/wiki/Genetic_algorithm
[4] Tambien estuvimos en contacto con otros grupos durante los das que trabajamos en los laboratorios de
la facultad. As, estuvimos en contacto con los grupos de:
Marta Ponzoni, Victoria Elizalde, Santiago Avenda
no;
Martn Page, Martn Fernandez, Gonzalo Castillo;
Sergio Gonz
alez, Emiliano Gonz
alez,
Gaston Krasny, Jonathan Tapicer
Matias Grunberg, Pablo Rozanski
con quienes compartimos los laboratorios y con otras inquietudes propias de los resultados de las experiencias.
37