3

I have really been struggling to solve this problem. This is the problem:

Given a string describing the circuit, calculate the total resistance of the circuit.

Here is an example:

  • input: 3 5 S
  • expected output: 8

The operands in the string are trailed by the operator, denoting if the resistors are either in Series or Parallel. However let's analyze a more complicated circuit:

  • input: 3 5 S 0 P 3 2 S P
  • expected output: 0

Step by step:

  1. The 3 5 S at the beginning of the input gives us 8 and hence the first intermediate step is the string 8 0 P 3 2 S P.
  2. 8 0 P gives us 0, as one resistor is short-circuited and consequently we get 0 3 2 S P.
  3. 3 2 P is 5.
  4. and finally 0 5 P is 0.

Here is my attempt. I tried using recursion as it seemed like a problem that can be solved that way. Firstly I wrote a helper function:

def new_resistance(a,b,c):
if c == '':
    if int(a) == 0 or int(b) == 0:
        return 0
    else:
        return 1/(1/int(a) + 1/int(b))
else:
    return int(a) + int(b)

And the function that calculates the newn resistance of the circuit:

def resistance(array):
if isinstance(array, int):
    return array
else:
    if isinstance(array,list):
        temp = array
    else:
        temp = array.split(" ")
    i = 0
    while True:
        try:
            a = new_resistance(temp[i], temp[i+1], temp[i+2])
        except Exception as e:
            i += 1            
        if len(temp[i+3:]) == 0:
            return resistance(new_resistance(temp[i], temp[i+1], temp[i+2]))
        else:
            return resistance(temp[:i] + [new_resistance(temp[i], temp[i+1], temp[i+2])] + temp[i+3:])

The idea behind the program is to start at the beginning of the list and calculate the resistance of the first three elements of the list, then to append them at the beginning of a new list (without the three elements) and call the function again with the new list. Do this until only a single integer remains and return the integers.

Any help is appreciated.


UPDATE:

The solution to the problem, using a stack and a parser similar to a NPR parser.

operator_list = set('PS')

def resistance(circuit):
  temp = circuit.split(" ")
  stack = []
  for char in temp:
      if char in operator_list:
          a = new_resistance(stack.pop(), stack.pop(), char)
          print(a)
          stack.append(a)
      else:
          print(char)
          stack.append(char)
  return stack[-1]

def new_resistance(a,b,c):
  if c == 'P':
      if float(a) == 0 or float(b) == 0:
          return 0
      else:
          return 1/(1/float(a) + 1/float(b))
  else:
      return float(a) + float(b)

circuit = '3 5 S 0 P 3 2 S P'
resistance(circuit)

# 3
# 5
# 8.0
# 0
# 0
# 3
# 2
# 5.0
# 0

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124

4 Answers4

2

Your program, or more specifically your parser, seems to be relying on the Reverse Polish Notation, which in turn is a small variant of the Normal Polish Notation. Simply put, the RPN is an abstract representation where the operators of an arithmetical expression follow their operands, unlike in the Normal Polish Notation where the operators precede their operands. Parsers based on this representation can be easily implemented by using stacks (and usually do not need to interpret parentheses).

If you are tasked with developing that parser you may get some input from the Wikipedia article I linked above.

Acsor
  • 1,011
  • 2
  • 13
  • 26
  • I remember solving a similar problem to this one where I had to convert, and now that i think of it, the problem is extremely similar. Thank you. – blaz stojanovic Oct 08 '17 at 09:34
2

The problem is that once you reach 0 3 2 S P, you cannot simply take the first 3 elements. You need to look for number number S_or_P, wherever it is in the string.

You can use a regex for this task:

import re

circuit = '3 5 S 0 P 3 2 S P'

pattern = re.compile('(\d+) +(\d+) +([SP])')

def parallel_or_serie(m):
  a, b, sp = m.groups()
  if sp == 'S':
    return str(int(a) + int(b))
  else:
    if a == '0' or b == '0':
      return '0'
    else:
      return str(1/(1/int(a) + 1/int(b)))

while True:
  print(circuit)
  tmp = circuit
  circuit = re.sub(pattern, parallel_or_serie, circuit, count=1)
  if tmp == circuit:
    break

# 3 5 S 0 P 3 2 S P
# 8 0 P 3 2 S P
# 0 3 2 S P
# 0 5 P
# 0

Note that 1 1 P will output 0.5. You could replace int by float and modify the regex in order to parse floats.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
0

Credits to @none who first recognized the RPN.

Old memories came to my mind. I was playing with the FORTH language on 8-bit computers in 1980s. OK, back to Python:

circuit = '3 5 S 0 P 3 2 S P'

stack = []
for n in circuit.split():
    if n == 'S':
        r1 = stack.pop()
        r2 = stack.pop()
        stack.append(r1+r2)
    elif n == 'P':
        r1 = stack.pop()
        r2 = stack.pop()
        stack.append(0.0 if (r1 == 0 or r2 == 0) else 1/(1/r1+1/r2))
    else:
        stack.append(float(n))

assert len(stack) == 1    
print(stack[0])
VPfB
  • 14,927
  • 6
  • 41
  • 75
0
  1. On in the spirit of VPfB for any combination of serial parallel (not only in pairs)

     def calculateresistor(dataString):
     stack = []
     r = []
     cicuit=dataString
     for n in circuit.split():
         if n == 'S':
             stackSize=size(stack)
             if size(stack)>=2:
                 for k in range(0,size(stack)-1):
                     r.append(float(stack.pop()))
                     r.append(float(stack.pop()))
                     stack.append((r[-1]+r[-2]))
         elif n == 'P':
             stackSize=size(stack)
             if size(stack)>=2:
                 for k in range(0,size(stack)-1):
                     r.append(float(stack.pop()))
                     r.append(float(stack.pop()))
                     r.append(0.0 if (r[-1] == 0 or r[-2] == 0) else (1/(1/r[-1]+1/r[-2])))
                     stack.append(r[-1])
         else:
             stack.append(float(n))
     assert len(stack) == 1
     return(stack)