Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 7604

Teaching and learning resources • Re: Super-cheap Computing Cluster for Learning

$
0
0
The result was

Code:

$ ./go24 # Pi B+ 700 MHzAdvent of Code 2024 Day 24 Crossed Wires (GOMAXPROCS=1)Part 1 The z wires output 568353998Part 2 Swap wires brp,bwv,dmk,dph,jbj,jnf,nfk,pgkTotal execution time 548.010919033 seconds.
Shy looked shyly at the output and meowed, but the answer is wrong.
After some quick edits the program reported

Code:

$ ./go24Advent of Code 2024 Day 24 Crossed Wires (GOMAXPROCS=1)Part 1 The z wires output 61495910098126Part 2 Swap wires css,cwt,gdd,jmv,pqt,z05,z09,z37Total execution time 127.31932476 seconds.
which not only is the correct answer but faster.

Since

127.32 / 4.6935 = 27.127

the speed is now in line with the 31.42 ratio of the Pi chart calculations.

viewtopic.php?p=2253106#p2253106

For reference the 32-bit Go code is

Code:

/*  Advent of Code 2024 Day 24 Crossed Wires    Written 2025 by Eric Olson    Parallel go version.  One topological sort per call to loss.    Added int64 types where needed for 32-bit targets.    Increase esize if this produces wrong answers.  Increase ksize    if it fails to produce any answers.  */package mainimport ("time"; . "os"; . "fmt"; "math/rand"; "strings"; "bufio"    "sort"; "runtime"; "sync")var tictime time.Timefunc tic(){    tictime=time.Now()}func toc() float64 {    now:=time.Now()    elapsed:=now.Sub(tictime)    return elapsed.Seconds()}   type byte=uint8const esize=20const ksize=10var (xstart=0; ystart=0; zstart=0)var (xbits=0; ybits=0; zbits=0)var myrnd=rand.New(rand.NewSource(time.Now().UnixNano()))var ncpus=runtime.GOMAXPROCS(0)func check(ip *int,s string,p string) bool {    var i=*ip    if len(s)<i+len(p) {        return false    }    for k:=0;k<len(p);k++ {        if s[k+i]!=p[k] {            return false        }    }    i+=len(p)    *ip=i    return true}func scanint(ip *int,s string) int {    var i=*ip    const (d0='0'; d9='9'; minus='-')    var (r=0; iold=i; m=-1)    for i<len(s) {        var d=s[i]        if iold==i&&d==minus {            m=1        } else if d>=d0 && d<=d9 {            r=r*10-int(d-d0)        } else {            break        }        i+=1    }    *ip=i    return m*r}func wire2num(stab []string,w string) int {    var (ai=0; bi=len(stab); cold=-1)    for {        var ci=(bi+ai)/2        if ci==cold {            break        }        if stab[ci]<w {            ai=ci        } else if stab[ci]>w {            bi=ci        } else {            return ci        }        cold=ci    }    return -1}func setinput(xp *int64,s string) {    var x=*xp    var (i=1; iold=i)    var j=scanint(&i,s)    if iold==i {        Printf("Can't find input bitnumber in %s\n",s)        Exit(1)    }    if !check(&i,s,": ") {        Printf("Missing : delimiter in %s\n",s)        Exit(1)    }    iold=i    var b=scanint(&i,s)    if iold==i {        Printf("Can't find input bit value in %s\n",s)        Exit(1)    }    if b<0||b>1 {        Printf("Bit value out of range in %s\n",s)        Exit(1)    }    var p=(int64(1)<<j)    if s[0]=='x' {        if xbits<=j {            xbits=j+1        }    }    if s[0]=='y' {        if ybits<=j {            ybits=j+1        }    }    if b==1 {        x|=p    } else {        x&=^p    }    *xp=x}type optype=func(x bool,y bool) boolfunc g_AND(x bool,y bool) bool {    return x&&y}func g_OR(x bool,y bool) bool {    return x||y}func g_XOR(x bool,y bool) bool {    return x!=y}var g_OP=[3]optype{g_AND,g_OR,g_XOR}var s_OP=[3]string{"AND","OR","XOR"}type gspec struct {    x1,x2,y int    f1,f2 bool    op optype}func getgate(stab []string,s string) gspec {    var v=strings.Split(s," ")    if len(v)!=5 {        Printf("Gate %s doesn't have 4 fields!\n",s)        Exit(1)    }    var r gspec    r.x1=wire2num(stab,v[0])    for i:=range s_OP {        if v[1]==s_OP[i] {            r.op=g_OP[i]        }    }    if r.op==nil {        Printf("Gate %s unrecognizable operation!\n",s)        Exit(1)    }    r.x2=wire2num(stab,v[2])    if v[3]!="->" {        Printf("Gate %s missing -> assignment!\n",s)        Exit(1)    }    r.y=wire2num(stab,v[4])    return r}func mkorder(stab []string,gates []gspec) []int {    var order=make([]int,len(gates))    var (op=0; oq=0)    setfn:=func(fnp *bool,c byte){        if c=='x'||c=='y' {            *fnp=false        } else {            *fnp=true        }    }    for i:=range gates {        setfn(&gates[i].f1,stab[gates[i].x1][0])        setfn(&gates[i].f2,stab[gates[i].x2][0])        if !gates[i].f1&&!gates[i].f2 {            order[oq]=i            oq+=1        }    }    var leaf=make([][]int,len(stab))    for i:=range gates {        var r=&gates[i]        leaf[r.x1]=append(leaf[r.x1],i)        leaf[r.x2]=append(leaf[r.x2],i)    }    for op<oq {        var i=order[op]        var r=&gates[i]        if len(leaf[r.y])==0 {            op+=1        } else {            for _,j:=range leaf[r.y] {                if gates[j].x1==r.y {                    gates[j].f1=false                    if !gates[j].f2 {                        order[oq]=j                        oq+=1                    }                } else if gates[j].x2==r.y {                    gates[j].f2=false                    if !gates[j].f1 {                        order[oq]=j                        oq+=1                    }                }            }            op+=1        }    }    return order}func rungates(order []int,mem []bool,gates []gspec,x int64,y int64) int64 {    for j:=0;j<xbits;j++ {        mem[xstart+j]=(x&1)==1        x>>=1    }    for j:=0;j<ybits;j++ {        mem[ystart+j]=(y&1)==1        y>>=1    }    for i:=range order {        var r=gates[order[i]]        var x1=mem[r.x1]        var x2=mem[r.x2]        var y=r.op(x1,x2)        mem[r.y]=y    }    var p int64=1    var p1 int64=0    for j:=0;j<zbits;j++ {        if mem[zstart+j] {            p1+=p        }        p*=2    }    return p1}func part1(stab []string,gates []gspec,inputs []string) int64 {    var (x int64=0; y int64=0)    for _,s:=range inputs {        if s[0]=='x' {            setinput(&x,s)        } else if s[0]=='y' {            setinput(&y,s)        } else {            Printf("Unknown register input in %s\n",s)            Exit(1)        }    }    return rungates(mkorder(stab,gates),        make([]bool,len(stab)),gates,x,y)}type xyspec struct {    x,y int64}func loss(stab []string,gates []gspec,ensemble []xyspec) int64 {    var order=mkorder(stab,gates)    var mem=make([]bool,len(stab))    var r int64=0    for i:=range ensemble {        var x=ensemble[i].x        var y=ensemble[i].y        var z=rungates(order,mem,gates,x,y)        var e=x+y-z        if e>=0 { r+=e } else { r-=e }        x=y    }    return r}type lspec struct {    l int64    i,j int}type rspec struct {    i,j int}func tryswap(stab []string,gates []gspec,        ensemble []xyspec,d int) []int {    var losses=make([]lspec,len(gates)*(len(gates)-1)/2)    var ij=make([]rspec,ncpus+1)    ij[0]=rspec{1,0}    for n:=1;n<=ncpus;n++ {        var (i=ij[n-1].i; j=ij[n-1].j)        var na=i*(i-1)/2+j        var nb=n*len(losses)/ncpus        var delta=nb-na        for {            if i-j>delta {                j+=delta                ij[n]=rspec{i,j}                break            }            delta-=i-j            i+=1; j=0        }    }    var rfound rspec    var rfzero=rspec{0,0}    rfound=rfzero    mklosses:=func(n int,C *sync.WaitGroup) {        var gatesn=make([]gspec,len(gates))        copy(gatesn,gates)        var (i=ij[n-1].i; j=ij[n-1].j)        var (ib=ij[n].i; jb=ij[n].j)        var k=i*(i-1)/2+j        for {            gatesn[i].y,gatesn[j].y=gatesn[j].y,gatesn[i].y            var ts=loss(stab,gatesn,ensemble)            gatesn[i].y,gatesn[j].y=gatesn[j].y,gatesn[i].y            if ts==0 {                rfound=rspec{i,j}            } else {                losses[k].i=i                losses[k].j=j                losses[k].l=ts                k+=1            }            j+=1            if j>=i {                j=0; i+=1            }            if (i==ib&&j==jb)||rfound!=rfzero {                break            }        }        if C!=nil { C.Done() }    }    var C sync.WaitGroup    for n:=1;n<ncpus;n++ {        C.Add(1)        go mklosses(n,&C)    }    mklosses(ncpus,nil)    C.Wait()    var rf=rfound    if rf!=rfzero {        var r=make([]int,2)        r[0]=rf.i        r[1]=rf.j        return r    }    var klen=len(losses)    losseslt:=func(i,j int) bool {        return losses[i].l<losses[j].l    }    sort.Slice(losses,losseslt)    if klen>ksize {        klen=ksize    }    if d==1 {        var r []int        return r    }    for k:=0;k<klen;k++ {        var i=losses[k].i        var j=losses[k].j        gates[i].y,gates[j].y=gates[j].y,gates[i].y        var r=tryswap(stab,gates,ensemble,d-1)        gates[i].y,gates[j].y=gates[j].y,gates[i].y        if len(r)>0 {            r=append(r,i)            r=append(r,j)            return r        }    }    var r []int    return r}func mkensemble() []xyspec {    var ensemble=make([]xyspec,esize)    var xmask=int64(1)<<xbits-1    var ymask=int64(1)<<ybits-1    for i:=range ensemble {        var x=myrnd.Int63()&xmask        var y=myrnd.Int63()&ymask        ensemble[i]=xyspec{x,y}    }    return ensemble}func part2(stab []string,gates []gspec) string {    var ensemble=mkensemble()    var r=tryswap(stab,gates,ensemble,4)    var wll=make([]string,len(r))    for i:=range wll {        wll[i]=stab[gates[r[i]].y]    }    sort.Strings(wll)    var p2=""    for i:=range wll {        if i>0 {            p2+=","+wll[i]        } else {            p2=wll[i]        }    }    return p2}func dowork(){    raw,err:=Open("day24.txt")    for err!=nil {        Printf("Error opening input for reading!\n")        Exit(1)    }    fp:=bufio.NewScanner(raw)    var inputs []string    for fp.Scan() {        s:=fp.Text()        if len(s)==0 {            break        }        inputs=append(inputs,s)    }    var assign []string    for fp.Scan() {        s:=fp.Text()        assign=append(assign,s)    }    var slen=len(inputs)+len(assign)    var stab=make([]string,slen)    var i=0    for _,s:=range inputs {        stab[i]=s[0:3]        i+=1    }    for _,s:=range assign {        var v=strings.Split(s," ")        stab[i]=v[4]        i+=1    }    sort.Strings(stab)    var x00="x00"    xstart=wire2num(stab,x00)    var y00="y00"    ystart=wire2num(stab,y00)    var z00="z00"    zstart=wire2num(stab,z00)    zbits=len(stab)-zstart    var gates=make([]gspec,len(assign))    i=0    for _,s:=range assign {        gates[i]=getgate(stab,s)        i+=1    }    var p1=part1(stab,gates,inputs)    var p2=part2(stab,gates)    Printf("Part 1 The z wires output %d\n",p1)    Printf("Part 2 Swap wires %s\n",p2)}func main(){    tic()    Printf("Advent of Code 2024 Day 24 Crossed Wires "+        "(GOMAXPROCS=%d)\n\n",ncpus)    dowork()    t:=toc()    Printf("\nTotal execution time %g seconds.\n",t)    Exit(0)}
This afternoon Purr showed me a working version of part 1 in C. Scratchy was unimpressed and meowed the only thing of importance is a parallel MPI implementation of the tryswap routine.

Statistics: Posted by ejolson — Wed May 21, 2025 4:10 am



Viewing all articles
Browse latest Browse all 7604

Trending Articles