Skip to content

Commit

Permalink
Added Step by Step Reasoning for Solving Process
Browse files Browse the repository at this point in the history
  • Loading branch information
Saptak625 committed Feb 4, 2023
1 parent db486fb commit 84ad9f4
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 27 deletions.
50 changes: 38 additions & 12 deletions circuit_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class CircuitSolver:
def __init__(self, circuitCode):
self.components = {}
self.compileCircuit(circuitCode)
self.stepByStepReasoning = ''
self.stepByStepReasoning = []

def compileCircuitFromFile(fileName):
with open(fileName, 'r') as circuitCode:
Expand Down Expand Up @@ -38,7 +38,7 @@ def compileCircuit(self, circuitCode):
subcomponentString = p
if c[0] == 'r':
#Create new resistor
r = Resistor(parameters[0], voltage = voltage, current = current, resistance = resistance)
r = Resistor(parameters[0], self.writeReasoning, voltage = voltage, current = current, resistance = resistance)
self.components[r.name] = r
else:
#Create new Leg
Expand All @@ -50,7 +50,7 @@ def compileCircuit(self, circuitCode):
raise Exception(f'Must declare whether Leg "{parameters[0].upper()}" is series or parallel.')
subcomponentNames = subcomponentString.split(',')[:-1]
subcomponents = [self.components[n.upper()] for n in subcomponentNames]
l = Leg(parameters[0], circuitType, subcomponents, voltage = voltage, current = current, resistance = resistance)
l = Leg(parameters[0], self.writeReasoning, circuitType, subcomponents, voltage = voltage, current = current, resistance = resistance)
self.components[l.name] = l
else:
#Return Statement
Expand All @@ -65,22 +65,48 @@ def solve(self):
if not self.circuit.solve():
raise Exception('Either not enough information passed resulting in ambigious case or algorithm missing solving method')

def showCircuit(self, showLegs = True, showResistors = True):
print(self.__str__(showLegs, showResistors))
def writeReasoning(self, reasoning):
self.stepByStepReasoning.append(reasoning)

def __str__(self, showLegs = True, showResistors = True):
def getStepByStepReasoning(self, showVoltageSteps = True, showCurrentSteps = True, showResistanceSteps = True):
out = []
i = 1
for r in self.stepByStepReasoning:
write = False
if "Ohm's Law" in r:
if 'its voltage' in r and showVoltageSteps:
write = True
elif 'its current' in r and showCurrentSteps:
write = True
elif 'its resistance' in r and showResistanceSteps:
write = True
elif 'Voltage' in r and showVoltageSteps:
write = True
elif 'Current' in r and showCurrentSteps:
write = True
elif 'Resistance' in r and showResistanceSteps:
write = True
if write:
out.append(f'{i}. {r}')
i += 1
return '\n'.join(out)

def showStepByStepReasoning(self, showVoltageSteps = True, showCurrentSteps = True, showResistanceSteps = True):
print(self.getStepByStepReasoning(showVoltageSteps=showVoltageSteps, showCurrentSteps=showCurrentSteps, showResistanceSteps=showResistanceSteps))

def __str__(self, showLegs = True, showResistors = True, showVoltage = True, showCurrent = True, showResistance = True):
def sortKeys(name):
return 0 if name[0].upper() == 'L' else 1, sum([ord(i) for i in name[1:]])
componentNames = sorted(list(self.components.keys()), key = sortKeys)
out = str(self.circuit)
out = self.circuit.__str__(showVoltage=showVoltage, showCurrent=showCurrent, showResistance=showResistance)
for n in componentNames:
if not ((not showLegs and n[0] == 'L') or (not showResistors and n[0] == 'R') or n == self.circuit.name):
out += f'\n\n{self.components[n]}'
out += f'\n\n{self.components[n].__str__(showVoltage=showVoltage, showCurrent=showCurrent, showResistance=showResistance)}'
pass
return out

def __repr__(self, showLegs = True, showResistors = True):
return self.__str__(showLegs, showResistors)
def __repr__(self, showLegs = True, showResistors = True, showVoltage = True, showCurrent = True, showResistance = True):
return self.__str__(showLegs=showLegs, showResistors=showResistors, showVoltage=showVoltage, showCurrent=showCurrent, showResistance=showResistance)

def writeReasoning(reasoning):
self.stepByStepReasoning += reasoning;
def showCircuit(self, showLegs = True, showResistors = True, showVoltage = True, showCurrent = True, showResistance = True):
print(self.__str__(showLegs=showLegs, showResistors=showResistors, showVoltage=showVoltage, showCurrent=showCurrent, showResistance=showResistance))
55 changes: 41 additions & 14 deletions component.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ class CircuitType(enum.Enum):
parallel = 2

class Resistor:
def __init__(self, name, voltage = None, current = None, resistance = None, allowBypass = False):
def __init__(self, name, writeReasoning, voltage = None, current = None, resistance = None, allowBypass = False):
self.name = name.upper()
self.writeReasoning = writeReasoning
if not(voltage or current or resistance) and not allowBypass:
raise Exception(f"Voltage, current, or resistance needs to be known for Resistor '{self.name}'")
self.voltage = voltage
Expand All @@ -28,27 +29,37 @@ def ohmsLaw(self):
if self.voltage and self.current:
self.resistance = self.voltage / self.current
self.resistanceReason = "Ohm's Law"
self.writeReasoning(f'{self.name} has a voltage of {round(self.voltage, 5)} Volts and a current of {round(self.current, 5)} Amps, so its resistance is {round(self.resistance, 5)} Ohms. (Ohm\'s Law)')
elif self.voltage and self.resistance:
self.current = self.voltage / self.resistance
self.currentReason = "Ohm's Law"
self.writeReasoning(f'{self.name} has a voltage of {round(self.voltage, 5)} Volts, and a resistance of {round(self.resistance, 5)} Ohms, so its current is {round(self.current, 5)} Amps. (Ohm\'s Law)')
else:
self.voltage = self.current * self.resistance
self.voltageReason = "Ohm's Law"
self.writeReasoning(f'{self.name} has a current of {round(self.current, 5)} Amps and a resistance of {round(self.resistance, 5)} Ohms, so its voltage is {round(self.voltage, 5)} Volts. (Ohm\'s Law)')
return True
return False

def __repr__(self, pretty = False):
return self.__str__(pretty = pretty)
def __repr__(self, pretty = False, showVoltage = True, showCurrent = True, showResistance = True):
return self.__str__(pretty = pretty, showVoltage = showVoltage, showCurrent = showCurrent, showResistance = showResistance)

def __str__(self, pretty = True):
def __str__(self, pretty = True, showVoltage = True, showCurrent = True, showResistance = True):
if pretty:
return f'{self.name}:\nVoltage: {round(self.voltage, 5)} Volts ({self.voltageReason})\nCurrent: {round(self.current, 5)} Amps ({self.currentReason})\nResistance: {round(self.resistance, 5)} Ohms ({self.resistanceReason})'
props = [f'Voltage: {round(self.voltage, 5)} Volts ({self.voltageReason})', f'Current: {round(self.current, 5)} Amps ({self.currentReason})', f'Resistance: {round(self.resistance, 5)} Ohms ({self.resistanceReason})']
props = [p for i, p in enumerate(props) if [showVoltage, showCurrent, showResistance][i]]
return f'{self.name}:\n' + '\n'.join(props)
else:
return f'Resistor({self.name}, [{self.voltage}-{self.voltageReason}, {self.current}-{self.currentReason}, {self.resistance}-{self.resistanceReason}])'
props = [f'{self.voltage}-{self.voltageReason}', f'{self.current}-{self.currentReason}', f'{self.resistance}-{self.resistanceReason}']
props = [p for i, p in enumerate(props) if [showVoltage, showCurrent, showResistance][i]]
if props:
return f'Resistor({self.name}, {props})'
else:
return f'Resistor({self.name})'

class Leg(Resistor):
def __init__(self, name, circuitType, subcomponents, voltage = None, current = None, resistance = None):
super().__init__(name, voltage = voltage, current = current, resistance = resistance, allowBypass = True)
def __init__(self, name, writeReasoning, circuitType, subcomponents, voltage = None, current = None, resistance = None):
super().__init__(name, writeReasoning, voltage = voltage, current = current, resistance = resistance, allowBypass = True)
self.circuitType = circuitType
if len(subcomponents) == 0:
raise Exception(f"Leg {self.name} must have at least 1 subresistor.")
Expand Down Expand Up @@ -84,10 +95,12 @@ def equalityRules(self):
if not self.current:
self.current = equalityCurrent
self.currentReason = 'Series Current Equality'
self.writeReasoning(f'{self.name} has a current of {round(self.current, 5)} Amps because all subcomponents have the same current. (Series Current Equality)')
for s in self.subcomponents:
if not s.current:
s.current = equalityCurrent
s.currentReason = 'Series Current Equality'
s.writeReasoning(f'{s.name} has a current of {round(s.current, 5)} Amps because all subcomponents have the same current. (Series Current Equality)')
return True
else:
testSum = len([True for s in self.subcomponents if s.voltage]) + (1 if self.voltage else 0)
Expand All @@ -96,10 +109,12 @@ def equalityRules(self):
if not self.voltage:
self.voltage = equalityVoltage
self.voltageReason = 'Parallel Voltage Equality'
self.writeReasoning(f'{self.name} has a voltage of {round(self.voltage, 5)} Volts because all subcomponents have the same voltage. (Parallel Voltage Equality)')
for s in self.subcomponents:
if not s.voltage:
s.voltage = equalityVoltage
s.voltageReason = 'Parallel Voltage Equality'
s.writeReasoning(f'{s.name} has a voltage of {round(s.voltage, 5)} Volts because all subcomponents have the same voltage. (Parallel Voltage Equality)')
return True
return False

Expand All @@ -110,6 +125,7 @@ def sumRules(self):
if not self.voltage: #Voltage for leg not provided. Add all subvoltages.
self.voltage = sum([s.voltage for s in self.subcomponents])
self.voltageReason = 'Series Voltage Sum'
self.writeReasoning(f'{self.name} has a voltage of {round(self.voltage, 5)} Volts because it is equal to the sum of the voltages of all subcomponents {", ".join([s.name+" ("+str(round(s.voltage, 5))+" Volts)" for s in self.subcomponents])}. (Series Voltage Sum)')
else:
subcomponentVoltageSum = 0
targetSubcomponent = None
Expand All @@ -120,12 +136,14 @@ def sumRules(self):
targetSubcomponent = s
targetSubcomponent.voltage = self.voltage - subcomponentVoltageSum
targetSubcomponent.voltageReason = 'Series Voltage Sum'
self.writeReasoning(f'{targetSubcomponent.name} has a voltage of {round(targetSubcomponent.voltage, 5)} Volts because it is equal to the difference between the voltage of {self.name} ({round(self.voltage, 5)} Volts) and the sum of the voltages of all other subcomponents ({", ".join([s.name for s in self.subcomponents if s != targetSubcomponent])}) ({round(subcomponentVoltageSum, 5)} Volts). (Series Voltage Sum)')
return True
testResistanceSum = len([True for s in self.subcomponents if s.resistance]) + (1 if self.resistance else 0)
if testResistanceSum == len(self.subcomponents):
if not self.resistance: #Resistance for leg not provided. Add all subresistances.
self.resistance = sum([s.resistance for s in self.subcomponents])
self.resistanceReason = 'Series Resistance Sum'
self.writeReasoning(f'{self.name} has a resistance of {round(self.resistance, 5)} Ohms because it is equal to the sum of the resistances of all subcomponents {", ".join([s.name+" ("+str(round(s.resistance, 5))+" Ohms)" for s in self.subcomponents])}. (Series Resistance Sum)')
else:
subcomponentResistanceSum = 0
targetSubcomponent = None
Expand All @@ -136,13 +154,15 @@ def sumRules(self):
targetSubcomponent = s
targetSubcomponent.resistance = self.resistance - subcomponentResistanceSum
targetSubcomponent.resistanceReason = 'Series Resistance Sum'
self.writeReasoning(f'{targetSubcomponent.name} has a resistance of {round(targetSubcomponent.resistance, 5)} Ohms because it is equal to the difference between the resistance of {self.name} ({round(self.resistance, 5)} Ohms) and the sum of the resistances of all other subcomponents ({", ".join([s.name for s in self.subcomponents if s != targetSubcomponent])}) ({round(subcomponentResistanceSum, 5)} Ohms). (Series Resistance Sum)')
return True
else:
testCurrentSum = len([True for s in self.subcomponents if s.current]) + (1 if self.current else 0)
if testCurrentSum == len(self.subcomponents):
if not self.current: #Current for leg not provided. Add all subcurrents.
self.current = sum([s.current for s in self.subcomponents])
self.currentReason = 'Parallel Current Sum'
self.writeReasoning(f'{self.name} has a current of {round(self.current, 5)} Amps because it is equal to the sum of the currents of all subcomponents {", ".join([s.name+" ("+str(round(s.current, 5))+" Amps)" for s in self.subcomponents])}. (Parallel Current Sum)')
else:
subcomponentCurrentSum = 0
targetSubcomponent = None
Expand All @@ -153,12 +173,14 @@ def sumRules(self):
targetSubcomponent = s
targetSubcomponent.current = self.current - subcomponentCurrentSum
targetSubcomponent.currentReason = 'Parallel Current Sum'
self.writeReasoning(f'{targetSubcomponent.name} has a current of {round(targetSubcomponent.current, 5)} Amps because it is equal to the difference between the current of {self.name} ({round(self.current, 5)} Amps) and the sum of the currents of all other subcomponents ({", ".join([s.name for s in self.subcomponents if s != targetSubcomponent])}) ({round(subcomponentCurrentSum, 5)} Amps). (Parallel Current Sum)')
return True
testResistanceSum = len([True for s in self.subcomponents if s.resistance]) + (1 if self.resistance else 0)
if testResistanceSum == len(self.subcomponents):
if not self.resistance: #Resistance for leg not provided. Add all subresistances using 1/r formula.
self.resistance = 1/sum([(1/s.resistance) for s in self.subcomponents])
self.resistanceReason = 'Parallel Resistance Sum'
self.writeReasoning(f'{self.name} has a resistance of {round(self.resistance, 5)} Ohms because it is equal to the reciprocal of the sum of the reciprocals of the resistances of all subcomponents {", ".join([s.name+" ("+str(round(s.resistance, 5))+" Ohms)" for s in self.subcomponents])}. (Parallel Resistance Sum)')
else:
subcomponentResistanceSum = 0
targetSubcomponent = None
Expand All @@ -169,14 +191,19 @@ def sumRules(self):
targetSubcomponent = s
targetSubcomponent.resistance = 1/((1/self.resistance) - subcomponentResistanceSum)
targetSubcomponent.resistanceReason = 'Parallel Resistance Sum'
self.writeReasoning(f'{targetSubcomponent.name} has a resistance of {round(targetSubcomponent.resistance, 5)} Ohms because it is equal to the reciprocal of the difference between the reciprocal of the resistance of {self.name} ({round(self.resistance, 5)} Ohms) and the sum of the reciprocals of the resistances of all other subcomponents ({", ".join([s.name for s in self.subcomponents if s != targetSubcomponent])}) ({round(subcomponentResistanceSum, 5)} Ohms). (Parallel Resistance Sum)')
return True
return False

def __repr__(self, pretty = False):
return self.__str__(pretty=pretty)

def __str__(self, pretty = True):
def __str__(self, pretty = True, showVoltage = True, showCurrent = True, showResistance = True):
if pretty:
return f'{self.name}:\nVoltage: {round(self.voltage, 5)} Volts ({self.voltageReason})\nCurrent: {round(self.current, 5)} Amps ({self.currentReason})\nResistance: {round(self.resistance, 5)} Ohms ({self.resistanceReason})'
props = [f'Voltage: {round(self.voltage, 5)} Volts ({self.voltageReason})', f'Current: {round(self.current, 5)} Amps ({self.currentReason})', f'Resistance: {round(self.resistance, 5)} Ohms ({self.resistanceReason})']
props = [p for i, p in enumerate(props) if [showVoltage, showCurrent, showResistance][i]]
return f'{self.name}:\n' + '\n'.join(props)
else:
return f'Leg({self.name}, {self.circuitType}, {self.subcomponents}, [{self.voltage}-{self.voltageReason}, {self.current}-{self.currentReason}, {self.resistance}-{self.resistanceReason}])'
props = [f'{self.voltage}-{self.voltageReason}', f'{self.current}-{self.currentReason}', f'{self.resistance}-{self.resistanceReason}']
props = [p for i, p in enumerate(props) if [showVoltage, showCurrent, showResistance][i]]
if props:
return f'Leg({self.name}, {self.circuitType}, {[s.name for s in self.subcomponents]}, {props})'
else:
return f'Leg({self.name}, {self.circuitType}, {[s.name for s in self.subcomponents]})'
4 changes: 3 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

circuitSolver = CircuitSolver.compileCircuitFromFile('circuit.crc')
circuitSolver.solve()
circuitSolver.showCircuit()
circuitSolver.showStepByStepReasoning(showVoltageSteps=False, showCurrentSteps=False, showResistanceSteps=True)
print('\n\n')
circuitSolver.showCircuit(showVoltage=False, showCurrent=False, showResistance=True, showLegs=True, showResistors=False)

0 comments on commit 84ad9f4

Please sign in to comment.