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

Reply via email to