Mostrando entradas con la etiqueta python. Mostrar todas las entradas
Mostrando entradas con la etiqueta python. Mostrar todas las entradas

miércoles, 14 de mayo de 2014

Erlang-C en Python - Herramientas para el Cálculo de Probabilidad de Espera y Número de Agentes...


Aquí dejo una página con una explicación muy buena sobre los Erlangs, y unas rutinas en Python que escribí una tarde para calcular probabilidades de espera, número de agentes, nieveles de servicio u temas relacionados con los Erlang. No soy para nada experto en el tema, simplemente necesitaba validar unos números y las calculadoras que encontraba no me servían (o yo no supe usarlas)  / Here's a link to a very good explanation about the Erlangs, and a few Python routines I put together one evening to compute traffic intensity, agent occupancy, probability of waiting, average speed of answer (ASA), service level, agents needed and other Erlang-C related stuff. I'm not an expert on this at all, just needed to validate some data and the calculators I came across didn't suit me (or I just didn't know how to use them)



from math import pow,factorial,log,exp

def PowerFact(b,e):
    ## Returns b^e / e! used everywhere else in the model
    return pow(b,e)/factorial(e)

def erlangC(m,u):
    ## Returns the probability a call waits.
    ## m is the agent count
    ## u is the traffic intensity
    suma=0
    for k in range(0,m):
        suma+=PowerFact(u,k)
    erlang=PowerFact(u,m)/((PowerFact(u,m))+(1-p)*suma)
    return erlang

def SLA(m,u,T,target):
    ## Returns the average speed of answer
    ## m is the agent count
    ## u is the traffic intensity
    ## T is the average call time
    ## target is the target answer time
    return (1 - erlangC(m, u) * exp(-(m-u)*(target/T)))

def ASA(m,u,T):
    ## Returns the average speed of answer (ASA)
    ## m is the agent counts.
    ## u is the traffic intensity
    ## T is the average call time
    return erlangC(m, u)*(T/(m-u))

def agentsNeeded(u,T,targetSLA,target):
    ## Returns the number of agents needed to reach given SLA
    ## u is the traffic intensity
    ## T is the average call time
    ## target is the target answer time
    ## targetSLA % calls answered under target time
    level=0
    m=1
    while level < targetSLA:
        level=SLA(m,u,T,target)
        m+=1
    return m-1
  
################

calls=360.     # number of calls in a given time interval
interval=1800. # the time interval, in secs (1800 s == 30 minutes)
landa=calls/interval
T=240.         # average call duration, in secs
m=55           # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'secs, average speed of answer (ASA)'
target=15
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'secs'
nivel=0.7
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'secs'

################

print "-"*10

calls=300.      # number of calls in a given time interval
interval=900. # the time interval, in secs (here 15 minutes)
landa=calls/interval
T=180.        # average call duration, in secs
m=65            # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'secs, average speed of answer (ASA)'
target=45
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'secs'
nivel=0.95
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'secs'

################

print "-"*10

calls=650.      # number of calls in a given time interval
interval=3600. # the time interval, in secs (here 1h)
landa=calls/interval
T=150.        # average call duration, in secs
m=34            # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'secs, average speed of answer (ASA)'
target=30
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'secs'
nivel=0.5
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'secs'

################

print "-"*16

calls=20.      # number of calls in a given time interval
interval=3600. # the time interval, in secs (1800 s == 30 minutes)
landa=calls/interval
T=1800.        # average call duration, in secs
m=11           # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'secs, average speed of answer (ASA)'
target=3600
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'secs'
nivel=0.8
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'secs'

################

print "-"*16

calls=4280.      # number of calls in a given time interval
interval=168.    # the time interval, in hours (7dx24h = 168)
landa=calls/interval
T=1./6           # average call duration, in hours
m=6           # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'hrs, average speed of answer (ASA)'
target=0.5
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'hrs'
nivel=0.87
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'hrs'

################

print "-"*16

calls=1282.    # number of calls in a given time interval
interval=60.   # the time interval, in hours (5dx12h = 60)
landa=calls/interval
T=0.75         # average call duration, in hours
m=18           # number of agents
u=landa*T      # traffic intensity
p=u/m          # agent occupancy

print landa,'calls/interval'
print u,'traffic intensity'
print m,'agents'
print p,'agent occupancy'
print erlangC(m,u)*100,'% probability of waiting, ErlangC'
print ASA(m,u,T),'hrs, average speed of answer (ASA)'
target=1
print SLA(m,u,T,target)*100,'% probability call is answered in less than',target,'hrs'
nivel=0.89
print agentsNeeded(u,T,nivel,target),'agents needed to reach',nivel*100,'% calls answered in <',target,'hrs'



SALIDA

0.2 calls/interval
48.0 traffic intensity
55 agents
0.872727272727 agent occupancy
23.8700936378 % probability of waiting, ErlangC
8.18403210439 secs, average speed of answer (ASA)
84.5883092171 % probability call is answered in less than 15 secs
52 agents needed to reach 70.0 % calls answered in < 15 secs
----------
0.333333333333 calls/interval
60.0 traffic intensity
65 agents
0.923076923077 agent occupancy
42.0072292571 % probability of waiting, ErlangC
15.1226025326 secs, average speed of answer (ASA)
87.964727315 % probability call is answered in less than 45 secs
68 agents needed to reach 95.0 % calls answered in < 45 secs
----------
0.180555555556 calls/interval
27.0833333333 traffic intensity
34 agents
0.796568627451 agent occupancy
14.3013055995 % probability of waiting, ErlangC
3.10148796134 secs, average speed of answer (ASA)
96.4140712702 % probability call is answered in less than 30 secs
27 agents needed to reach 50.0 % calls answered in < 30 secs
----------------
0.00555555555556 calls/interval
10.0 traffic intensity
11 agents
0.909090909091 agent occupancy
68.2118204689 % probability of waiting, ErlangC
1227.81276844 secs, average speed of answer (ASA)
90.7685339568 % probability call is answered in less than 3600 secs
11 agents needed to reach 80.0 % calls answered in < 3600 secs
----------------
25.4761904762 calls/interval
4.24603174603 traffic intensity
6 agents
0.707671957672 agent occupancy
34.8436314992 % probability of waiting, ErlangC
0.0331093330988 hrs, average speed of answer (ASA)
99.8193211949 % probability call is answered in less than 0.5 hrs
5 agents needed to reach 87.0 % calls answered in < 0.5 hrs
----------------
21.3666666667 calls/interval
16.025 traffic intensity
18 agents
0.890277777778 agent occupancy
53.5967359233 % probability of waiting, ErlangC
0.20353190857 hrs, average speed of answer (ASA)
96.1496854898 % probability call is answered in less than 1 hrs
18 agents needed to reach 89.0 % calls answered in < 1 hrs




 

domingo, 19 de febrero de 2012

MIT Python Tutor - Depurador Python Online

Con la ayuda de este depurador Python del MIT, podremos ver paso a paso qué ocurre con nuestros programas



y sobre todo nos permitirá comprender cómo funcionan las asignaciones entre estructuras de datos









Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos de Google Reader y desde Twitter.

domingo, 17 de enero de 2010

Anagramas con Python

En el post anterior comentaba como me pongo a ratos con el libro Python for Software Design, versión impresa del conocido How to Think Like a Computer Scientist. Como ya indiqué, se trata de una fantástica introducción al lenguaje Python del profesor Allen B. Downey.

En el ejercicio 4 del capítulo 12 propone un ejercicio para explorar un diccionario en busca de anagramas. Leemos en la Wikipedia que un anagrama es una palabra o frase que resulta de la transposición de letras de otra palabra o frase. Por ejemplo roma, amor, omar y mora son anagramas, así como lámina y animal.

El objetivo de la práctica es escribir una serie de funciones que impriman todos los conjuntos de anagramas del fichero (en nuestro caso un diccionario español, que podemos obtener en este enlace). Estas son las mías

from string import join,maketrans

def encuentraAnagramas():
anagramas={}
fin = open("E:\\ES.txt")
intab = "áéíóú"
outtab = "aeiou"
trantab = maketrans(intab, outtab)
for line in fin:
word = line.strip()
word2 = word.translate(trantab)
l=list(word2)
l.sort()
clave=join(l,'')
try:
anagramas[clave].append(word)
except KeyError:
anagramas[clave]=[word]
return anagramas

def buscador(palabra,diccionario):
lpalabra=list(palabra)
lpalabra.sort()
clave=join(lpalabra,'')
return(diccionario[clave])


>>> f=encuentraAnagramas()
>>> buscador('monja',f)
['jamón', 'mojan', 'monja']
>>> buscador('roma',f)
['amor', 'armo', 'armó', 'mora', 'ramo', 'roma']
>>> buscador('estados',f)
['dotases', 'estados']
>>> buscador('rebuscado',f)
['becuadros', 'rebuscado']
¿Cómo funciona esto? El truco, si es que hay alguno, consiste en usar una de las estructuras de datos más potentes de Python, los diccionarios, para recorrer la lista de palabras e ir formando un diccionario (lo que se denomina un hash en Perl o array asociativo en PHP) que conecte una clave con la lista de todas las palabras que sean anagramas entre sí. Pero, ¿cómo podemos organizar 'becuadros' y 'rebuscado' para que nos de una clave única de búsqueda? La respuesta la encontré hace tiempo leyendo un artículo de A.K.Dewdney en su estupenda columna 'Computer Recreations' de 'Scientific American' ('Investigación y Ciencia'): ordenar las letras de las palabras alfabéticamente. Veamos como funciona:
>>> p='retarais'
>>> l=list(p)
>>> l
['r', 'e', 't', 'a', 'r', 'a', 'i', 's']
>>> l.sort()
>>> l
['a', 'a', 'e', 'i', 'r', 'r', 's', 't']
>>> f['aaeirrst']
['arterias', 'arter\xedas', 'estirara', 'estirar\xe1', 'estriara', 'estriar\xe1', 'iterar\xe1s', 'rater\xedas', 'restar\xeda', 'retarais', 'retar\xedas', 'traer\xedas']
>>> for item in _:
print item,
arterias arterías estirara estirará estriara estriará iterarás raterías restaría retarais retarías traerías
Todas estas palabras, cuando sus letras son ordenadas alfabéticamente, convergen en 'aaeirrst'. Esa es la clave de búsqueda para los anagramas que podemos formar con estas letras. Con todas las piezas juntas, no es difícil encontrar cuales son las listas más grandes de anagramas... para lo que usaremos otro diccionario:
d={}
for i in f.keys():
cantidad=len(f[i])
try:
d[cantidad].append(f[i])
except KeyError:
d[cantidad]=[f[i]]
for i in d.keys()[-4:]:
print 'De longitud ',i
for lista in d[i]:
print '(',
for elem in lista:
print elem,
print ')',
print
Y estas son las listas de anagramas resultantes:

De longitud 11
( arresta arteras rastrea rateras restara restará retaras retarás retrasa traerás trasera ) ( artesonar atraernos atronarse nortearas nortearás ratearnos ratoneras sortearan sortearán tornearas tornearás ) ( alertos estarlo loteras orlaste relatos resalto resaltó soltaré soltera toleras tráelos ) ( entro entró norte rento rentó roten tenor terno torne torné treno ) ( espora operas opresa posaré repaso repasó reposa separo separó áspero óperas ) ( apretar pararte partear partera reparta reptara reptará trapear trapera trepara trepará ) ( entréis estiren estríen inertes inserte inserté interés rentéis rientes sentiré tírense ) ( cansaré cenaras cenarás cesaran cesarán encaras ensacar nacerás nácares secaran secarán ) ( enteros ernesto estreno estrenó eternos noreste nortees sorteen teneros tenores tornees ) ( caernos caserón cesaron coserán cráneos córneas encaros enrosca escoran roncase secaron ) ( amiste emitas estima matéis mesita metáis metías semita temáis temías timase ) ( ensarte ensarté enteras entesar entrase esteran estrena eternas rentase retasen sentaré )

De longitud 12
( canteros cantores cartones constaré contarse conteras contraes cornetas cortasen encastró roncaste troncase ) ( acaréis aceráis acerías caerías careáis casería cesaría escaria reacias recaías saciaré secaría ) ( alcores caerlos caleros calores colarse corales coserla créalos cóleras escolar laceros secarlo ) ( arreste arresté erraste esterar rastree rastreé restaré retarse retrase retrasé traerse térreas ) ( ardemos dameros daremos demoras desamor desarmo desarmó domarse maderos medrosa moderas redomas ) ( arrestan ensartar entraras entrarás narraste rastrean rentaras rentarás restaran restarán retrasan transaré ) ( abatirse abiertas baterías batieras estibara estibará estiraba estriaba rabietas rebatáis rebatías retabais ) ( acares aceras caerás careas casaré casera cesara cesará resaca sacaré secara secará ) ( asentir entráis estiran estrían inserta instaré rentáis retinas sentirá tiernas tirasen triasen ) ( entrarais entrarías estiraran estirarán estriaran estriarán insertara insertará rentarais rentarías restarían ternarias ) ( arterias arterías estirara estirará estriara estriará iterarás raterías restaría retarais retarías traerías )

De longitud 14
( artesón ensarto ensartó norteas notarse ratones rentosa rotasen sonarte sortean tornase torneas toserán tráenos )

De longitud 16
( arresto arrestó arteros ostrera rastreo rastreó rateros retraso retrasó rotarse sortear terrosa toreras torrase traeros trasero ) ( albores balsero besarlo boleras labores rebalso rebalsó resbalo resbaló roblase róbales róbelas saberlo salobre ábrelos árboles )







Alguien muy cercano y muy querido me dijo que estos post le resultaban inspiradores y le recordaban a los ejercicios de estilo Raymond Queneau (fundador de Oulipo), así que si no has entendido nada de todo esto espero que al menos disfrutes con el resultado ;-) Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos, y a partir de ahora desde Twitter o Friendfeed.

jueves, 14 de enero de 2010

Juegos de Palabras con Python

A ratos estoy con el libro Python for Software Design, versión impresa del conocido How to Think Like a Computer Scientist, una fantástica introducción al lenguaje Python del profesor Allen B. Downey.

Concretamente el capítulo 9, "Juegos de palabras", propone una serie de ejercicios en los que poner en práctica lo aprendido en los capítulos precedentes. En primer lugar nos enseña a abrir y leer un fichero de texto línea a línea

filein = open('words.txt')
for line in filein:
word = line.strip()
print word
Y a partir de aquí pide que desarrollemos funciones que recorran un diccionario (el fichero ES.txt) encontrando palabras de longitud igual a...
def de_longitud(n):
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if len(line)==n+1:
print word,
o mayores que...
def mayores_que(n):
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if len(line)>n+1:
print word,
un determinado valor, que no usen una determinada letra...
def has_no_e(palabra):
return (not 'e' in palabra)
o letras en general...
def avoids(letras,palabra):
for l in letras:
if l in palabra:
return False
return True
o que usen un conjunto de ellas...
def uses_all(letras,palabra):
for l in letras:
if not l in palabra:
return False
return True
que busquen palíndromos (palabras capicúas)...
def is_palyndrome(palabra):
return palabra==palabra[::-1]
o palabras cuyas letras estén en orden alfabético...
def is_abecedarian(palabra):
letra_anterior=''
for letra_nueva in palabra:
if letra_nueva<letra_anterior:
return False
letra_anterior=letra_nueva
return True

def is_abecedarian2(palabra):
letra_anterior='z'
for letra_nueva in palabra:
if letra_nueva>letra_anterior:
return False
letra_anterior=letra_nueva
return True

Una vez desarrolladas estas funciones he buscado un diccionario español en formato texto (en este enlace los hay para múltiples idiomas) y he creado la siguiente batería de pruebas para probar las funciones desarrolladas
def demo():
"Imprime todas las palabras de la lista"
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
print word,

def demo2():
"Imprime palabras que no contienen la letra e"
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if has_no_e(word):
print word,

def demo3():
"Imprime palabras que evitan un conjunto de letras"
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if avoids('aeio',word): # "aents"
print word,

def demo4():
"Imprime palabras que usan un conjunto de letras"
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if uses_all('aeiouy',word):
print word,

def demo5():
"Imprime palabras cuyas letras están en orden alfabético"
from string import maketrans
fin = open("D:\\ES.txt")
intab = "áéíóúñ"
outtab = "aeioun"
trantab = maketrans(intab, outtab)
for line in fin:
word = line.strip()
word2=word.translate(trantab)
if is_abecedarian(word2):
print word,

def demo5_1():
"Imprime palabras cuyas letras están en orden alfabético inverso"
from string import maketrans
fin = open("D:\\ES.txt")
intab = "áéíóúñ"
outtab = "aeioun"
trantab = maketrans(intab, outtab)
for line in fin:
word = line.strip()
word2=word.translate(trantab)
if is_abecedarian2(word2):
print word,

def demo6():
"Imprime palabras capicúas"
fin = open("D:\\ES.txt")
for line in fin:
word = line.strip()
if is_palyndrome(word):
print word,
Y finalmente lo he ejecutado
print "\n\nPalabras de más de 21 caracteres"
mayores_que(21)
print "\n\nPalabras de 20 o más caracteres"
mayores_que(19)
print "\n\nPalabras capicúas"
demo6()
print "\n\nPalabras cuyas letras están en orden alfabético"
demo5()
print "\n\nPalabras cuyas letras están en orden alfabético inverso"
demo5_1()
print "\n\nPalabras que usan aeiouy"
demo4()
Siendo este el resultado:

Palabras de más de 21 caracteres
internacionalizaríamos internacionalizándolas internacionalizándoles internacionalizándolos

Palabras de 20 o más caracteres
anticonstitucionales antiproporcionalidad circunstanciadamente contrarreclamaciones descongestionaríamos extraterritorialidad inconstitucionalidad internacionalizabais internacionalizarais internacionalizarlas internacionalizarles internacionalizarlos internacionalizarnos internacionalizaréis internacionalizarían internacionalizarías internacionalizaseis malintencionadamente pentagonododecaedros precondicionamientos subdesarrolladamente bienintencionadamente desproporcionadamente electromagnéticamente intercontinentalmente internacionalizaremos internacionalizaríais internacionalizasteis internacionalizábamos internacionalizándola internacionalizándole internacionalizándolo internacionalizándome internacionalizándoos internacionalizándose internacionalizándote internacionalizáramos internacionalizásemos internacionalizaríamos internacionalizándolas internacionalizándoles internacionalizándolos

Palabras capicúas
a b c d e f g h i j k l m n o p q r s t u v w x y z ñ ó ll ada ala ama ana ara asa ata aya dad efe eje ele eme ene ese eñe non ojo oro oso sus erre alela aviva azuza dañad debed nadan radar rajar rapar rasar rayar rever rotor sacas sagas salas sanas sayas sañas sedes seres solos somos sosos narran rallar selles adamada adatada recocer reconocer sometemos

Palabras cuyas letras están en orden alfabético
a b c d e f g h i j k l m n o p q r s t u v w x y z ñ ó ad ah al as ay be ce ch cu de di dé el en es ex fi ir ll lo mu no nu os su tu tú él ñu aes ahí ajo amo ano año bel bes bis bit ces clo coz del den des dio dos doy fin fió fío gis hoy hoz huy los luz mor muy nos abel afmo afín agio ajos amor amos anos años befo cegó cejo cejó celo ceno cenó ceño ciño ciñó cruz deis dejo dejó dijo dilo dios délo ello fijo fijó film filo fino finó flor gimo hijo hilo hiló loor motu ágil achín adiós afijo afino afinó bello celos ceños chino dejos demos dilos dimos dinos délos dénos ellos fijos filos finos hijos hilos himno afijos bellos chillo chilló chinos defino dennos himnos

Palabras cuyas letras están en orden alfabético inverso
a b c d e f g h i j k l m n o p q r s t u v w x y z ñ ó da fe ge ha he id ji ka la le ll me mi mí ni oh oí pe pi ro se si so sé sí te ti té un va ve vi xi ya ye yo fea iba ida kif lea lee lid lié lía líe mea meé mía míe nea oca oda ola ole olé olí oía oíd pie pon pía píe rea red roa roe rol ron roo roí ría ríe sea sed sol son tea tic toa ton tía una une uní usa use uso usé usó uña vea ved vid vía yod yol zoo leed liba liga mica mida miga oiga ojea ojee ojeé oled olla olía onda oída peca pica pida poca poda pone rica rifa rife rifé rige roba roca roda roed roja roma roía roña seca seda sida siga soba soda sofá soga soja sola solí soma soné soñé teca toba toca toda toga tole toma tome tomé trié tría tríe unge unid unja unía urea urge urja urna usía veda vida viga volé yoga yola yuca yuta yute zeda zoca zona ojeda olida plica polca polea poned ponga ponla ponme ponía roiga rolla rolle rollé ronca ronda roída soled solía sonda tolla tonga troje unida volea volee voleé zumba zupia zurda zurra zurre zurro zurré zurró única úrica roñica solida sólida sónica tromba tronca tónica zurrón

Palabras que usan 'aeiouy'
atribuyendo atribuyeron neoyorquina ayuntamiento concluyerais constituyera contribuyera neoyorquinas obstruyerais reconstituya retribuyamos suprayectivo atribuyéndole atribuyéndome atribuyéndose atribuyéndote atribuyésemos ayuntamientos constituyeran constituyeras construyerais contribuyeran contribuyeras eyaculaciones reconstituyan reconstituyas suprayectivos yuxtaponiendo yuxtapusieron atribuyéndoles constituyerais contribuyerais reconstituyera retribuyéndola retribuyéramos multiproyectiva reconstituyamos reconstituyeran reconstituyeras reconstruyerais redistribuyamos retribuyéndolas yuxtaposiciones yuxtapusiésemos multiproyectivas reconstituyerais reconstituyéndola reconstituyéramos redistribuyéramos reconstituyéndolas

¡¡¡Que ustedes lo disfruten!!!





Fuente: Python for Software Design, versión impresa del conocido How to Think Like a Computer Scientist. Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos, y a partir de ahora desde Twitter o Friendfeed.

miércoles, 13 de enero de 2010

Explorando Divisores Potentes con Python

A través de los compartidos de Jose Antonio Prado Bassas me encontré ayer con este curioso reto del blog Espejo Lúdico en el que juega con los divisores propios de un número.

Los divisores propios de un número son sus divisores menos el propio número. Así, por ejemplo, los divisores propios de 12 son 1, 2, 3, 4 y 6. Pues bien, si tomamos los divisores propios de 24: 1, 2, 3, 4, 6, 8 y 12 y los multiplicamos

1 * 2 * 3 * 4 * 6 * 8 * 12 = 13824

obtenemos 13824, que es potencia del propio 24 (en concreto, 24 al cubo). El post planteaba el siguiente reto
hay hasta seis números más de dos cifras con esa propiedad (por supuesto el exponente no tiene por qué ser un cubo). ¿Sabrías descubrirlos?
Bueno. Aquí hay un problemilla para explorar con Python. Primero cree una función que devuelve una lista de los divisores propios de un número
def divisoresPropios(n):
lista=[]
for i in range(1,(n/2)+1):
if (n%i)==0:
lista.append(i)
return lista

>>> divisoresPropios(6)
[1, 2, 3]
>>> divisoresPropios(12)
[1, 2, 3, 4, 6]
>>> divisoresPropios(15)
[1, 3, 5]
>>> divisoresPropios(24)
[1, 2, 3, 4, 6, 8, 12]
Parece que funciona. Ahora transformamos un poco la función anterior para que en vez de devolver una lista de los divisores propios los vaya multiplicando y devuelva el resultado
def mulDivisoresPropios(n):
res=1
for i in range(1,(n/2)+1):
if (n%i)==0:
res*=i
return res

>>> mulDivisoresPropios(6)
6
>>> mulDivisoresPropios(12)
144
>>> mulDivisoresPropios(15)
15
>>> mulDivisoresPropios(24)
13824
Ya casi está. Definimos una función que toma un número y el múltiplo de sus divisores propios, y busca si se da algún caso en el que el número elevado a alguna potencia sea igual al múltiplo antes calculado.
def esDivisorPotente(num,mul):
for potencia in range(2,num):
res=pow(num,potencia)
if res==mul:
print num,'^',potencia,'=',res,
return True
if res>mul:
return False
Veamos cuales son los números de dos cifras que cumplen esta condición
>>> for i in range(1,101):
if esDivisorPotente(i,mulDivisoresPropios(i)):
print

12 ^ 2 = 144
18 ^ 2 = 324
20 ^ 2 = 400
24 ^ 3 = 13824
28 ^ 2 = 784
30 ^ 3 = 27000
32 ^ 2 = 1024
40 ^ 3 = 64000
42 ^ 3 = 74088
44 ^ 2 = 1936
45 ^ 2 = 2025
48 ^ 4 = 5308416
50 ^ 2 = 2500
52 ^ 2 = 2704
54 ^ 3 = 157464
56 ^ 3 = 175616
60 ^ 5 = 777600000
63 ^ 2 = 3969
66 ^ 3 = 287496
68 ^ 2 = 4624
70 ^ 3 = 343000
72 ^ 5 = 1934917632
75 ^ 2 = 5625
76 ^ 2 = 5776
78 ^ 3 = 474552
80 ^ 4 = 40960000
84 ^ 5 = 4182119424
88 ^ 3 = 681472
90 ^ 5 = 5904900000
92 ^ 2 = 8464
96 ^ 5 = 8153726976
98 ^ 2 = 9604
99 ^ 2 = 9801
Ummm, salen más de 6. Ahora podemos adornar un poco más la cosa:
for i in range(90,101):
if esDivisorPotente(i,mulDivisoresPropios(i)):
lista=divisoresPropios(i)
print ' = ',
for i in range(len(lista)-1):
print lista[i],'*',
print lista[len(lista)-1]

90 ^ 5 = 5904900000 = 1 * 2 * 3 * 5 * 6 * 9 * 10 * 15 * 18 * 30 * 45
92 ^ 2 = 8464 = 1 * 2 * 4 * 23 * 46
96 ^ 5 = 8153726976 = 1 * 2 * 3 * 4 * 6 * 8 * 12 * 16 * 24 * 32 * 48
98 ^ 2 = 9604 = 1 * 2 * 7 * 14 * 49
99 ^ 2 = 9801 = 1 * 3 * 9 * 11 * 33
De hecho estos números no parecen escasear, así por ejemplo en el entorno al millón tenemos muchos números que cumplen con la condición
1000076 ^ 23 = 1001749462105722003405829447631732777649010002466398328988709223525747312767402349848863851215950119508215957162865997753165741643557502976  =  1 * 2 * 4 * 7 * 11 * 14 * 17 * 22 * 28 * 34 * 44 * 68 * 77 * 119 * 154 * 187 * 191 * 238 * 308 * 374 * 382 * 476 * 748 * 764 * 1309 * 1337 * 2101 * 2618 * 2674 * 3247 * 4202 * 5236 * 5348 * 6494 * 8404 * 12988 * 14707 * 22729 * 29414 * 35717 * 45458 * 58828 * 71434 * 90916 * 142868 * 250019 * 500038





Fuente: Espejo Lúdico a través de los compartidos de Jose Antonio Prado Bassas. Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos, y a partir de ahora desde Twitter o Friendfeed.

viernes, 14 de agosto de 2009

Python para niños con RUR-PLE

Hace unos días comenté la existencia de PythonTurtle, un entorno de programación gráfico con el que enseñar el lenguaje de programación Python a los niños (y los no tan niños) a través de la denominada geometría de la tortuga.

Pues bien, a través de las Hacker News de Y-Combinator encuentro RUR-PLE, un entorno similar en el que podemos dibujar un laberinto y dar instrucciones a un robot para que explore el "mundo" virtual creado por nosotros.


Podemos incluso cambiar la foto del robot y poner la nuestra, y trae un tutorial muy completo... en inglés. Muy, muy divertido.

RUR-PLE se puede descargar aquí. Fuente: lshift vía Hacker News de Y-Combinator. Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos. Durante la redacción de este post no se han maltratado robots.

viernes, 7 de agosto de 2009

PythonTurtle, un entorno para enseñar programación a los niños (y a los mayores :-)

Hace un par de días descubrí PythonTurtle, un intérprete de Python que proporciona un entorno gráfico con el que explorar la programación de ordenadores a través de la denominada geometría de la tortuga, un sistema de creación de gráficos vectoriales por ordenador característico del lenguage Logo.

PythonTurtle viene acompañado de un breve tutorial gráfico donde se explican nociones elementales de Python a través de múltiples ejemplos.

Lo bueno es que a los pocos minutos uno ya está explorando y pintando con la cosa. Después de dibujar unas cuantas espirales

for i in range(10,200,5):
go(i)
turn(90)

for i in range(10,200,5):
go(i)
turn(120)

for i in range(10,200,5):
go(i)
turn(95)


y estrellas
def estrella(lados,long):
for i in range(lados):
turn(-60)
go(long)
turn(120)
go(long)
turn((360./lados)-60)

for i in range(10):
estrella(3+i,10*i)

me animé y con un poco de recursión saqué estos tres fractalillos: un árbol un tanto robótico que habría que aderezar con un par de randoms...
def arbol(lado):
go(lado)
if lado>5:
turn(-45)
arbol(lado/2.)
turn(180)
go(lado/2.)
turn(-90)
arbol(lado/2.)
turn(180)
go(lado/2.)
turn(135)

arbol(100)

un copito de Koch...
def copo(long):
if long>20:
copo(long/3.)
turn(-60)
copo(long/3.)
turn(120)
copo(long/3.)
turn(-60)
copo(long/3.)
else:
go(long)

copo(100)
turn(120)
copo(100)
turn(120)
copo(100)


y una curva de Hilbert
def hilbert_L(n):
if n>1:
turn(90)
hilbert_R(n-1)
go(10)
turn(-90)
hilbert_L(n-1)
go(10)
hilbert_L(n-1)
turn(-90)
go(10)
hilbert_R(n-1)
turn(90)

def hilbert_R(n):
if n>1:
turn(-90)
hilbert_L(n-1)
go(10)
turn(90)
hilbert_R(n-1)
go(10)
hilbert_R(n-1)
turn(90)
go(10)
hilbert_L(n-1)
turn(-90)

hilbert_R(4)

Por cierto, que traducir para los chavales las órdenes de la tortuga al español es tan sencillo como
def avanza(unidades):
go(unidades)

def gira(angulo):
turn(angulo)

Podeis encontrar más enlaces sobre Python es este post que escribí el año pasado. ¡A pasarlo bien!

Nota importante: No quiero dar una impresión equivocada acerca de Python con este post. Aunque es el lenguaje ideal para un chaval, Python es también un lenguaje completo, "serio", que es usado por empresas y organizaciones del calibre de la NASA, ILM, Google o Ironport (Cisco).

PythonTurtle se puede descargar aquí (de momento sólo para Windows). Como siempre, gracias por venir. Si te gustó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más información acerca del RSS). También puedes seguirme a través de mis elementos compartidos. Durante la redacción de este post no se han maltratado tortugas.

viernes, 21 de noviembre de 2008

Concurso Cisco de Desarrollo sobre Plataforma AXP

Ya comentamos hace unos meses la nueva Plataforma de eXtensión de Aplicaciones de Cisco (AXP), una serie de blades que ejecutan una variante de Linux en algunos routers (concretamente en las Integrated Series 1800, 2800 y 3800). Esta plataforma permite integrar aplicaciones desarrolladas por terceros con los routers Cisco a través de las APIs certificadas disponibles en C, Python, Perl, y Java.

Pues bien, Cisco ha puesto en marcha el Cisco Developer Contest, un concurso para innovar y promocionar el concepto de la red como plataforma a través del cual invita a los desarrolladores a que "piensen dentro de la caja" ("think inside the box"). Es una oportunidad para desarrollar aplicaciones Linux sobre la Plataforma AXP y además se pueden ganar premios (hay $100,000 en juego).

El concurso se desarrollará en dos fases. La primera fase (entrega de propuestas) ya está en marcha y concluye el 12 de Enero de 2009. La segunda fase (de implementación) comenzará en febrero y concluirá en mayo de 2009. Dejo un enlace a las preguntas más frecuentes relacionadas con el concurso.

Fuente: Cisco Developer Contest. Como siempre, gracias por venir. Si te interesó el post puedes apuntarte a través del correo electrónico o por medio del feed RSS (más acerca del RSS).