Resistance network calculator: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|zkl}}: added code)
(→‎{{header|Go}}: Updated in line with the Python 'reference' entry and simplified by replacing *big.Rat with float64 throughout.)
Line 65: Line 65:
import (
import (
"fmt"
"fmt"
"math/big"
"math"
"strconv"
"strconv"
"strings"
"strings"
)
)


func gauss(a [][]*big.Rat, b []*big.Rat) []*big.Rat {
func argmax(m [][]float64, i int) int {
n := len(a)
col := make([]float64, len(m))
t := new(big.Rat)
max, maxx := -1.0, -1
u := new(big.Rat)
for x := 0; x < len(m); x++ {
col[x] = math.Abs(m[x][i])
if col[x] > max {
max = col[x]
maxx = x
}
}
return maxx
}

func gauss(m [][]float64) []float64 {
n, p := len(m), len(m[0])
for i := 0; i < n; i++ {
for i := 0; i < n; i++ {
t.Abs(a[i][i])
k := i + argmax(m[i:n], i)
k := i
m[i], m[k] = m[k], m[i]
for j := i + 1; j < n; j++ {
t := 1 / m[i][i]
if u.Abs(a[j][i]).Cmp(t) == 1 {
for j := i + 1; j < p; j++ {
t.Abs(a[j][i])
m[i][j] *= t
k = j
}
}
if k != i {
for j := i; j < n; j++ {
u.Set(a[i][j])
a[i][j].Set(a[k][j])
a[k][j].Set(u)
}
u.Set(b[i])
b[i].Set(b[k])
b[k].Set(u)
}
}
t.Set(u.Inv(a[i][i]))
for j := i + 1; j < n; j++ {
for j := i + 1; j < n; j++ {
a[i][j].Mul(a[i][j], t)
t = m[j][i]
for l := i + 1; l < p; l++ {
}
b[i].Mul(b[i], t)
m[j][l] -= t * m[i][l]
for j := i + 1; j < n; j++ {
t.Set(a[j][i])
for k := i + 1; k < n; k++ {
u.Mul(t, a[i][k])
a[j][k].Sub(a[j][k], u)
}
}
u.Mul(t, b[i])
b[j].Sub(b[j], u)
}
}
}
}
for i := n - 1; i >= 0; i-- {
for i := n - 1; i >= 0; i-- {
for j := 0; j < i; j++ {
for j := 0; j < i; j++ {
u.Mul(a[j][i], b[i])
m[j][p-1] -= m[j][i] * m[i][p-1]
b[j].Sub(b[j], u)
}
}
}
}
col := make([]float64, len(m))
return b
for x := 0; x < len(m); x++ {
col[x] = m[x][p-1]
}
return col
}
}


func network(n, k0, k1 int, s string) *big.Rat {
func network(n, k0, k1 int, s string) float64 {
a := make([][]*big.Rat, n)
m := make([][]float64, n)
for i := 0; i < n; i++ {
for i := 0; i < n; i++ {
a[i] = make([]*big.Rat, n)
m[i] = make([]float64, n+1)
for j := 0; j < n; j++ {
a[i][j] = new(big.Rat)
}
}
}
arr := strings.Split(s, "|")
for _, resistor := range strings.Split(s, "|") {
for _, resistor := range arr {
rarr := strings.Fields(resistor)
rarr := strings.Fields(resistor)
n1, _ := strconv.Atoi(rarr[0])
a, _ := strconv.Atoi(rarr[0])
n2, _ := strconv.Atoi(rarr[1])
b, _ := strconv.Atoi(rarr[1])
ri, _ := strconv.Atoi(rarr[2])
ri, _ := strconv.Atoi(rarr[2])
r := new(big.Rat).SetFrac64(1, int64(ri))
r := 1.0 / float64(ri)
a[n1][n1].Add(a[n1][n1], r)
m[a][a] += r
a[n2][n2].Add(a[n2][n2], r)
m[b][b] += r
if n1 > 0 {
if a > 0 {
a[n1][n2].Sub(a[n1][n2], r)
m[a][b] -= r
}
}
if n2 > 0 {
if b > 0 {
a[n2][n1].Sub(a[n2][n1], r)
m[b][a] -= r
}
}
}
}
a[k0][k0].SetInt64(1)
m[k0][k0] = 1
b := make([]*big.Rat, n)
m[k1][n] = 1
return gauss(m)[k1]
for i := 0; i < n; i++ {
b[i] = new(big.Rat)
}
b[k1].SetInt64(1)
return gauss(a, b)[k1]
}
}


func main() {
func main() {
var ra [4]*big.Rat
var fa [4]float64
ra[0] = network(7, 0, 1, "0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8")
fa[0] = network(7, 0, 1, "0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8")
ra[1] = network(9, 0, 8, "0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1")
fa[1] = network(9, 0, 8, "0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1")
ra[2] = network(16, 0, 15, "0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1")
fa[2] = network(16, 0, 15, "0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1")
ra[3] = network(4, 0, 3, "0 1 150|0 2 50|1 3 300|2 3 250")
fa[3] = network(4, 0, 3, "0 1 150|0 2 50|1 3 300|2 3 250")
for _, r := range ra {
for _, f := range fa {
s := r.String()
fmt.Printf("%.6g\n", f)
if strings.HasSuffix(s, "/1") {
fmt.Println(s[0 : len(s)-2])
} else {
fmt.Println(s)
}
}
}
}</lang>
}</lang>
Line 169: Line 150:
<pre>
<pre>
10
10
1.5
3/2
1.85714
13/7
180
180
</pre>
</pre>

Revision as of 15:38, 23 March 2019

Resistance network calculator is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Introduction

Calculate the resistance of any resistor network.

  • The network is stated with a string.
  • The resistors are separated by a vertical dash.
  • Each resistor has
    • a starting node
    • an ending node
    • a resistance


Background

Arbitrary Resistor Grid


Regular 3x3 mesh, using twelve one ohm resistors
0 - 1 - 2
|   |   | 
3 - 4 - 5
|   |   |
6 - 7 - 8 

Battery connection nodes: 0 and 8

assert 3/2 == network(9,0,8,"0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1")


Regular 4x4 mesh, using 24 one ohm resistors
 0 - 1 - 2 - 3
 |   |   |   |   
 4 - 5 - 6 - 7
 |   |   |   |
 8 - 9 -10 -11
 |   |   |   |
12 -13 -14 -15

Battery connection nodes: 0 and 15

assert 13/7 == network(16,0,15,"0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1")


Ten resistor network

Picture

Battery connection nodes: 0 and 1

assert 10 == network(7,0,1,"0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8")


Wheatstone network

Picture

This network is not possible to solve using the previous Resistance Calculator as there is no natural starting point.

assert 180 == network(4,0,3,"0 1 150|0 2 50|1 3 300|2 3 250")

Go

Translation of: Python

<lang go>package main

import (

   "fmt"
   "math"
   "strconv"
   "strings"

)

func argmax(m [][]float64, i int) int {

   col := make([]float64, len(m))
   max, maxx := -1.0, -1
   for x := 0; x < len(m); x++ {
       col[x] = math.Abs(m[x][i])
       if col[x] > max {
           max = col[x]
           maxx = x
       }
   }
   return maxx

}

func gauss(m [][]float64) []float64 {

   n, p := len(m), len(m[0])
   for i := 0; i < n; i++ {
       k := i + argmax(m[i:n], i)
       m[i], m[k] = m[k], m[i]
       t := 1 / m[i][i]
       for j := i + 1; j < p; j++ {
           m[i][j] *= t
       }
       for j := i + 1; j < n; j++ {
           t = m[j][i]
           for l := i + 1; l < p; l++ {
               m[j][l] -= t * m[i][l]
           }
       }
   }
   for i := n - 1; i >= 0; i-- {
       for j := 0; j < i; j++ {
           m[j][p-1] -= m[j][i] * m[i][p-1]
       }
   }
   col := make([]float64, len(m))
   for x := 0; x < len(m); x++ {
       col[x] = m[x][p-1]
   }
   return col

}

func network(n, k0, k1 int, s string) float64 {

   m := make([][]float64, n)
   for i := 0; i < n; i++ {
       m[i] = make([]float64, n+1)
   }
   for _, resistor := range strings.Split(s, "|") {
       rarr := strings.Fields(resistor)
       a, _ := strconv.Atoi(rarr[0])
       b, _ := strconv.Atoi(rarr[1])
       ri, _ := strconv.Atoi(rarr[2])
       r := 1.0 / float64(ri)
       m[a][a] += r
       m[b][b] += r
       if a > 0 {
           m[a][b] -= r
       }
       if b > 0 {
           m[b][a] -= r
       }
   }
   m[k0][k0] = 1
   m[k1][n] = 1
   return gauss(m)[k1]

}

func main() {

   var fa [4]float64
   fa[0] = network(7, 0, 1, "0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8")
   fa[1] = network(9, 0, 8, "0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1")
   fa[2] = network(16, 0, 15, "0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1")
   fa[3] = network(4, 0, 3, "0 1 150|0 2 50|1 3 300|2 3 250")
   for _, f := range fa {
       fmt.Printf("%.6g\n", f)
   }

}</lang>

Output:
10
1.5
1.85714
180

Python

<lang python>from fractions import Fraction

def argmax(m,i): col = [abs(row[i]) for row in m] return col.index(max(col))

def gauss(m): n, p = len(m), len(m[0]) for i in range(n): k = i + argmax(m[i:n],i) m[i], m[k] = m[k], m[i] t = 1 / m[i][i] for j in range(i + 1, p): m[i][j] *= t for j in range(i + 1, n): t = m[j][i] for k in range(i + 1, p): m[j][k] -= t * m[i][k] for i in range(n - 1, -1, -1): for j in range(i): m[j][-1] -= m[j][i] * m[i][-1] return [row[-1] for row in m]

def network(n,k0,k1,s): m = [[0] * (n+1) for i in range(n)] resistors = s.split('|') for resistor in resistors: a,b,r = resistor.split(' ') a,b,r = int(a), int(b), Fraction(1,int(r)) m[a][a] += r m[b][b] += r if a > 0: m[a][b] -= r if b > 0: m[b][a] -= r m[k0][k0] = Fraction(1, 1) m[k1][-1] = Fraction(1, 1) return gauss(m)[k1]

assert 10 == network(7,0,1,"0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8") assert 3/2 == network(3*3,0,3*3-1,"0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1") assert Fraction(13,7) == network(4*4,0,4*4-1,"0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1") assert 180 == network(4,0,3,"0 1 150|0 2 50|1 3 300|2 3 250")</lang>

zkl

Library: GSL

GNU Scientific Library

This a tweak of Resistor_mesh#zkl <lang zkl>var [const] GSL=Import.lib("zklGSL"); // libGSL (GNU Scientific Library)

fcn network(n,k0,k1,mesh){

  A:=GSL.Matrix(n,n);  // zero filled
  foreach resistor in (mesh.split("|")){
     a,b,r := resistor.split().apply("toInt");
     r=1.0/r;
     A[a,a]=A[a,a] + r;
     A[b,b]=A[b,b] + r;
     if(a>0) A[a,b]=A[a,b] - r;
     if(b>0) A[b,a]=A[b,a] - r;
  }
  b:=GSL.Vector(n);  // zero filled
  b[k1]=1;
  A.AxEQb(b)[k1];

}</lang> <lang zkl>network(7,0,1,"0 2 6|2 3 4|3 4 10|4 5 2|5 6 8|6 1 4|3 5 6|3 6 6|3 1 8|2 1 8") .println();

network(3*3,0,3*3-1,"0 1 1|1 2 1|3 4 1|4 5 1|6 7 1|7 8 1|0 3 1|3 6 1|1 4 1|4 7 1|2 5 1|5 8 1") .println();

network(4*4,0,4*4-1,"0 1 1|1 2 1|2 3 1|4 5 1|5 6 1|6 7 1|8 9 1|9 10 1|10 11 1|12 13 1|13 14 1|14 15 1|0 4 1|4 8 1|8 12 1|1 5 1|5 9 1|9 13 1|2 6 1|6 10 1|10 14 1|3 7 1|7 11 1|11 15 1") .println();

network(4,0,3,"0 1 150|0 2 50|1 3 300|2 3 250") .println();</lang>

Output:
10
1.5
1.85714
180