# este programa calcula la mejor disposici'on que se puede dar a una carga
# en la bodega de un avion, asumiendo que la bodega tiene un largo long_bodega
# la carga est'a pre almacenada en contenedores de longitud ancho_cont, de manera tal que se pued considerar 
# concentrada en su punto medio. Ademas la distancia al centro de sustentacion medida desde el inicio d ela bodega 
# es dist_cg.
# se asume como hipotesis de mejor solucion, a aquella que minimiza el momento de la carga total respecto del centro de sutentacion
# se calculan todas la variantes de carga posibles, para cada configuracion se calcula el momento y se busca el minimo
# la cantidad de cargas que se cargan inicialmente en w, limita severamente la ejecucion del programa ya que el calculo 
# de las posibles configuraciones tiene un crecimiento gobernado por el factorial de la cantidad de cargas

import matplotlib.pyplot as plt
from itertools import permutations
from time import time

#   tiempo con distintas cargas
#   3       0.159
#   4       0.18
#   5       0.20
#   6       0.22
#   7       0.23
#   8       0.30
#   9       1.21
#   10     10.76         
start=time()

#w=[300.,200.,310.,390.,290.,300.,305.,250.,300.]
w=[300.,200.,310.,390.,290.,300.,305.,250.,300.,287.]  # lista de cargas
d=[]                                                    # lista de distancias de loscontenedores
m=[]                                                    # lista para guardar la distrib de momentos inicial
long_bodega=28.0                                        # longitud bodega
ancho_cont=2.0                                          # ancho de contenedor
dist_cg=10.0                                            # distancia del centro de sustentacion

# se llena la lista de distancias de los baricentros de contenedores
# se llena una lista auxiliar de momentos de cada contenedor para graficar la condicion inicial
mom_tot=0.0
for i in range(len(w)):
    d.append(-dist_cg+(i*ancho_cont)+ancho_cont/2)      # guarda en d las distancias
    m.append(w[i]*d[i])                                 # guarda en m los momentos iniciales
    print 'Posicion({0}){1:>6.2f},{2:>5.2f}'.format(i,w[i],d[i])
    mom_tot=mom_tot+m[i]
print "Momento config. inicial:",mom_tot


# empieza el grafico
ancho_barra=1                                           # ancho de barra en grafico
fig = plt.figure(figsize=(10,5))                        # se genera el objeto fig (es una ventana) de 10 x 5
plt.subplots_adjust(wspace=0.5,hspace=0.5)              # se define la sepaaraciones de los subplots

# en la ventana fig, agregamos un grafico
# con la distribucion inicial de pesos
ax = fig.add_subplot(221)   # grafico 2 filas 2 columnas posicion 1
ax.set_xlabel('m')
ax.set_ylabel('kg')
ax.set_title('Distrib Inicial Pesos')
ax.bar(d, w, ancho_barra, label='Peso')

# en la ventana fig agregamos un segundo grafico
# con la distribucion inicial de momentos
bx = fig.add_subplot(222)   # grafico 2 filas 2 columnas posicion 2
bx.bar(d, m, ancho_barra, label='M')
bx.set_xlabel('m')
bx.set_ylabel('kgm')
bx.set_title('Distrib Inicial Momentos')


# ETAPA DE OPTIMIZACION
#genero una lista con los numero de orden de las cargas
# esta es la que usaremos como fuente para generar la permutaciones
orden=[]
orden=range(len(w))             # llenamos las lista con los ordinales hasta  len(w)

print "lista ORDEN", orden

# genero las permutaciones, la funcion me devuelve tuplas en g 
g = permutations(orden)

    
# como viene en tuplas, las pasamos a lista
permu=[]                            # creamos una lista vacia
for i in g:
    #print i
    permu.append(list(i))           # trasnformo cada tupla en lista

# cada elemento de la lista tiene internamente otra lista
# el conjunto  contiene todas las permutaciones sin repeticion que
# pueden hacerse con los elementos de la lista "orden"
# como inicialmente esta lleno con las posiciones ordinales de las cargas
# sus permutaciones representan todas las posibilidades de ordenamiento de las mimas

#busco la permutacion con minimo momento
m_min=1e10
per_min=[]
for i in range(len(permu)):
    m_tot=0
    # para cada permutacion (que queda en la variable i)
    for j in range(len(permu[i])):  # j variara entre 0 t el largo de la permutacion
        # para cada permutacion, leemos uno a uno cual es el nro de contenedor y guardamos en "puntero" 
        puntero=permu[i][j]
        #print puntero,
        m_tot=m_tot+w[puntero]*d[j]     #calcula el momento de esa permutacion acumulando el peso que esta en w
                                        # por la distancia que esta en d 
                                        # las posiciones son fijas y lo que cambia son los pesos
        #print w[puntero],"x",d[j],"+",
    #print i,m_tot,permu[i]
    if abs(m_tot)<=abs(m_min):          # busco el minimo
        m_min=m_tot
        per_min=permu[i]


print "Configuracion optima:",m_min,per_min

# grafico de distribucion optima de pesos
w_o=[]

# lleno la lista de pesos ordenados optimizados para poder graficar
# para el grafico uso la misma lista de distancias porque la geometria no cambio
for i in per_min:
    w_o.append(w[per_min[i]])
   
cx = fig.add_subplot(223)       # grafico 2 filas 2 columnas posicion 1
cx.set_xlabel('m')
cx.set_ylabel('kg')
cx.set_title('DISTRIB OPTIMIZADA PESOS')
cx.bar(d, w_o, ancho_barra, label='Peso')

m_o=[]
for i in range(len(w_o)):
    m_o.append(w_o[i]*d[i])                                 # guarda en m los momentos iniciales
    print 'Posicion({0}){1:>6.2f},{2:>5.2f}'.format(i,w[i],d[i])

dx = fig.add_subplot(224)       # grafico 2 filas 2 columnas posicion 1
dx.set_xlabel('m')
dx.set_ylabel('kg')
dx.set_title('DISTRIB OPTIMIZADA MOMENTOS')
dx.bar(d, m_o, ancho_barra, label='Peso')


print "Cantidad de cargas:", len(w)
print "Tiempo de ejecucion:",time()-start
print "Configuraciones evaluadas:",len(permu)

plt.show()

