OK, my suggestions:
I think the data model is fairly straight forward: a resistor network is defined by a list of resistor instances which can be represented by term of the form:
resistance(N1,R,N2)
or something similar. N1
and N2
are node labels, e.g., atoms like a
, b
, etc. and R
is the resistor value (a number). To keep things simple for now let’s assume N1 @< N2
, i.e., the labels are ordered, which can be done without any loss of generality.
The objective is to find “single resistance which is equivalent to the network”. One way of doing this is to iteratively replace a pair of resistors in the network by a single resistor until the network list consists of a single resistor. A slightly more general predicate might combine pairs of resistors until a minimum network is achieved, i.e., no further combinations can be found:
res_reduce(Rs,R) :-
res_combine(Rs,NRs), % combine two into one
res_reduce(NRs,R). % and repeat
res_reduce(Rs,Rs). % minimal network
So now the trick is to write rules which find and replace a pair of resistors in the list with a single value. Such a rule for parallel resistors might look like:
res_combine(Rs,[resistance(N1,Rn,N2)|NRs]) :-
select(resistance(N1,R1,N2),Rs,Rs1),
select(resistance(N1,R2,N2),Rs1,NRs),
!, % avoid duplicates due to order selected
Rn is (R1*R2)/(R1+R2).
This uses select/3
from library(lists)
which is autoloaded. If you’re going to use lists, this library provides many useful predicates.
The res_combine
rule for serial resistors is a little more complicated since it effectively removes a node from the network and you have to make sure no other resistor is connected to that node, but I’ll leave it to you as an exercise.
Example queries using your test network (using res_network
to define the network):
?- res_network(Rs),res_reduce(Rs,[EqR]).
Rs = [resistance(a, 100, c), resistance(a, 200, b), resistance(b, 300, c), resistance(c, 50, d)],
EqR = resistance(b, 200, d) ;
Rs = [resistance(a, 100, c), resistance(a, 200, b), resistance(b, 300, c), resistance(c, 50, d)],
EqR = resistance(a, 400r3, d) ;
false.
?- res_network(Rs),res_reduce(Rs,[resistance(a,R,T)]).
Rs = [resistance(a, 100, c), resistance(a, 200, b), resistance(b, 300, c), resistance(c, 50, d)],
R = 400r3,
T = d ;
false.
The first query finds two equivalent resistance values: 200
ohms between b
and d
and 400r3
(133.33..
) ohms between a
and c
. The second query looks for the equivalent resistance connected to node a
.
Does something like this meet your needs?