Hello
I'm writing a program to find an appropiate combination of resistances
to obtain a desired value of resistance. The program takes into account
how many resistances you have available and their resistance in ohms.
A short review of physics: resistors can be arranged in series or in
parallel. To obtain the equivalent resistance (that is, you could
replace those resistors with only one that had this resistance): if in
series: sum ohms; if in parallel 1/Req = 1/R1 + 1/R2.
Since this problem (as far as I can tell) requires to generate all
possible combinations (eliminating those that are impossible -ie:
requires 3 resistances of type A and you only have 2-), I'm trying to
make it run as fast as possible. So far I discovered that:
- Calling functions that return a value (ie: just "return
self.something") is slower than just grabbing the value from the class
- If you've got recursions, and you call them multiple times, you better
remember what they returned last time, otherwise it can consume a lot of
time (or to put it another way: don't go down the same road twice :)
- Psyco is nice :)
- The Python Profiler is really useful in these cases :)
Now, I was reading about decorators and noticed that some classes can
inherit from object. I thought it should make no difference in speed,
but, just because, I tried changing my class to inherit from object. Big
surprise, it *does* change things. I was wondering if somebody could
explain why it does? I find it quite weird!
Profiling normal:
4772989 function calls (3817173 primitive calls) in 54.433 CPU
seconds
Profiling all clases inherit from object:
4772989 function calls (3817173 primitive calls) in 51.151 CPU
seconds
But what's really really strange is that if one class inherits from
object but the other does not, the amount of calls varies!
Both "normal" classes:
1051803 4.609 0.000 4.609 0.000 resistPsyco.py:65(__cmp__)
78803 0.372 0.000 0.372 0.000 resistPsyco.py:85(__cmp__)
Resistencia inherits from object:
86306 0.402 0.000 0.402 0.000 resistPsyco.py:65(__cmp__)
1044300 4.879 0.000 4.879 0.000 resistPsyco.py:85(__cmp__)
Why does this happen?
I have attached the code, I hope that's fine. If you have any further
optimization suggestions I would be very glad to hear them :)
About the code:
- generarPos generates all possible resistances
- generarResist generates all possible from the initial resistances
- unico makes sure that there are no duplicates (equal resistance) -
This method was posted on the ASPN Cookbook
- ResistenciaB is the basic resistance, the ones you have available.
- Resistencia is composed of two resistances
- checkPosible checks that you can actually build this resistor
- getBasicasIni tells you how many resistors of x type you have used.
- resorig are the resistors you begin with
- rescant is the amount of each basic resistors you have
- Don't put many different resistors or a big amount of resistors,
otherwise the program may take veeeryyy long to run.
Please forgive any broken English. It's been too long since I last wrote
in it.
Thanks for your time!
Ismael
#import psyco
#psyco.profile()
class Resistencia(object):
def __init__(self, R1, R2, serie=True):
self.R1 = R1
self.R2 = R2
self.serie = serie
self.basicas = []
for i in rescant:
self.basicas.append(0)
self.posible = self.checkPosible()
self.resist = self.getResist()
def checkPosible(self):
for pos, r in enumerate(resorig):
a = self.basicas[pos] = self.getBasicasIni(r, pos)
if a > rescant[pos]:
return False
return True
def getResist(self):
if self.serie:
self.resist = self.R1.resist+self.R2.resist
else:
self.resist = int(1.0/(1.0/self.R1.resist+1.0/self.R2.resist))
if self.resist == 0:
self.resist = 1 ##Evito ZeroDivisionError!
return self.resist
def getResistExacta(self):
if self.serie:
return self.R1.getResistExacta()+self.R2.getResistExacta()
else:
return
(1.0/(1.0/self.R1.getResistExacta()+1.0/self.R2.getResistExacta()))
def getBasicas(self, resBpos):
return self.basicas[resBpos]
def getBasicasIni(self, resB, resBpos):
val = self.basicas[resBpos]
if val: return val
total = 0
if self.R1 == resB:
total += 1
else:
total += self.R1.getBasicasIni(resB, resBpos)
if self.R2 == resB:
total += 1
else:
total += self.R2.getBasicasIni(resB, resBpos)
return total
def __repr__(self):
if self.serie:
return "%s--%s" %(self.R1, self.R2)
else:
return "(%s //// %s)" %(self.R1, self.R2)
def __cmp__(self, otro):
return self.resist - otro.resist
class ResistenciaB:
def __init__(self, resist):
self.resist = resist
def getResistExacta(self):
return self.resist
def getResist(self):
return self.resist
def getBasicas(self, resB):
if self.resist == resB.resist:
return 1
return 0
def getBasicasIni(self, resB, resBpos):
if self.resist == resB.resist:
return 1
return 0
def __repr__(self):
return "-%s-" %(self.resist)
def __cmp__(self, otro):
return self.resist - otro.resist
def generarResist(listaRes):
resultado = []
for i in listaRes:
for j in listaRes:
r = Resistencia(i,j)
if r.posible:
resultado.append(r)
r = Resistencia(i,j, False)
if r.posible:
resultado.append(r)
return unico(resultado)
def unico(t):
t.sort()
last = t[0]
lasti = i = 1
while i < len(t):
if t[i] != last:
t[lasti] = last = t[i]
lasti += 1
i += 1
return t[:lasti]
def generarPos():
##Genera todas las posibles
todos = []
todos += resorig
todos += generarResist(resorig)
for i in range(sum(rescant)-2):
todos += generarResist(todos)
return unico(todos)
resorig = [ResistenciaB(100), ResistenciaB(200)]
rescant = [2, 4]
import time
def time1():
t1 = time.time()
a = generarPos()
t2 = time.time()
return t2-t1
_______________________________________________
Tutor maillist - Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor