ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

ejolson wrote:
Wed Dec 06, 2023 9:50 pm
The output on an Intel i3-550 was

Code: Select all

``````\$ julia day01.jl
Advent of Code 2023 Day 1 Trebuchet

Part 1 The sum of calibration values is 54968
Part 2 The English calibration value is 54094

Total execution time 0.289618602 seconds.
``````
which includes the just-in-time compilation.
The output on a Pi Zero is

Code: Select all

``````\$ julia day01.jl
Advent of Code 2023 Day 1 Trebuchet

Part 1 The sum of calibration values is 54968
Part 2 The English calibration value is 54094

Total execution time 7.539847265 seconds.
``````
which is slower but noticeably works and produces the correct answer.

Before teaching I had some time so I worked puzzle 2 and obtained

Code: Select all

``````\$ julia day02.jl
Advent of Code 2023 Day 2 Cube Conundrum

Part 1 The sum of the IDs is 2600
Part 2 The sum the powers is 86036

Total execution time 6.332537949 seconds.
``````
on the same Pi Zero.

For reference the code was

Code: Select all

``````#=  Advent of Code 2023 Day 2 Cube Conundrum
Written 2023 by Eric Olson =#

struct DoExit <: Exception
end

function gobble(s::String,m::String)::Tuple{String,Bool}
if length(s)<length(m)
return s,false
end
if s[1:length(m)]==m
return s[length(m)+1:end],true
end
return s,false
end

function getint(s::String)::Tuple{String,Int}
n=0
for i=1:length(s)
if s[i]>='0'&&s[i]<='9'
n=n*10+(s[i]-'0')
else
return s[i:end],n
end
end
return "",n
end

function getdraw(s::String)::Tuple{String,Vector{Int}}
r=s
z=zeros(Int,3)
while true
s,n=getint(s)
if n==0
return s,z
end
if begin s,f=gobble(s," red"); f end
z[1]=n
elseif begin s,f=gobble(s," green"); f end
z[2]=n
elseif begin s,f=gobble(s," blue"); f end
z[3]=n
end
if begin s,f=gobble(s,", "); !f end
if length(s)>0
if begin s,f=gobble(s,"; "); !f end
println("\$r\nUnable to parse draw!")
throw(DoExit())
end
end
return s,z
end
end
end

function getgame1(s::String)::Int
r=s
if begin s,f=gobble(s,"Game "); !f end
println("\$r\nDid not begin with Game!")
throw(DoExit())
end
if begin s,n=getint(s); n==0 end
println("\$r\nCould not parse game number!")
throw(DoExit())
end
if begin s,f=gobble(s,": "); !f end
println("\$r\nMissing : separator!")
throw(DoExit())
end
while length(s)>0
s,z=getdraw(s)
if z[1]>12||z[2]>13||z[3]>14
return 0
end
end
return n
end

function getgame2(s::String)::Int
r=s
if begin s,f=gobble(s,"Game "); !f end
println("\$r\nDid not begin with Game!")
throw(DoExit())
end
if begin s,n=getint(s); n==0 end
println("\$r\nCould not parse game number!")
throw(DoExit())
end
if begin s,f=gobble(s,": "); !f end
println("\$r\nMissing : separator!")
throw(DoExit())
end
zmin=zeros(Int,3)
while length(s)>0
s,z=getdraw(s)
for i=1:3
if zmin[i]<z[i]
zmin[i]=z[i]
end
end
end
return prod(zmin)
end

function partn(data,getgame)
r=0
for i=1:length(data)
r+=getgame(data[i])
end
return r
end

function doinit()
data=[]
open("day02.txt","r") do fp
end
p1=partn(data,getgame1)
p2=partn(data,getgame2)
println("Part 1 The sum of the IDs is ",p1)
println("Part 2 The sum the powers is ",p2)
end

function main()
t=@elapsed try
println("Advent of Code 2023 Day 2 Cube Conundrum\n")
doinit()
throw(DoExit())
catch r
if !isa(r,DoExit)
rethrow(r)
end
end
println("\nTotal execution time ",t," seconds.")
end

main()
``````
Although the end keyword is used as an index, none of the code was written by ChatGPT.
Last edited by ejolson on Fri Dec 08, 2023 9:32 pm, edited 2 times in total.

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

ejolson wrote:
Fri Dec 08, 2023 9:15 pm
I worked puzzle 2 and obtained

Code: Select all

``````\$ julia day02.jl
Advent of Code 2023 Day 2 Cube Conundrum

Part 1 The sum of the IDs is 2600
Part 2 The sum the powers is 86036

Total execution time 6.332537949 seconds.
``````
on the same Pi Zero.
The just-in-time compiler runs much faster after warming up. This can be seen when using Julia interactively on the Pi Zero.

Code: Select all

``````\$ julia
_
_       _ _(_)_     |  Documentation: https://docs.julialang.org
(_)     | (_) (_)    |
_ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` |  |
| | |_| | | | (_| |  |  Version 1.6.7 (2022-07-19)
_/ |\__'_|_|_|\__'_|  |
|__/                   |

julia> include("day02.jl")
Advent of Code 2023 Day 2 Cube Conundrum

Part 1 The sum of the IDs is 2600
Part 2 The sum the powers is 86036

Total execution time 6.235623485 seconds.

julia> main()
Advent of Code 2023 Day 2 Cube Conundrum

Part 1 The sum of the IDs is 2600
Part 2 The sum the powers is 86036

Total execution time 0.077048574 seconds.

julia> main()
Advent of Code 2023 Day 2 Cube Conundrum

Part 1 The sum of the IDs is 2600
Part 2 The sum the powers is 86036

Total execution time 0.077007574 seconds.
``````
Note the second and third runs are about 80 times faster than the first.

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

ejolson wrote:
Fri Dec 08, 2023 4:24 pm
I'd like to generate more data and scale the problem up for lots of the puzzles so the computation is large enough a parallel algorithm could be efficient.
Day 8 run time can be cut in half by multithreading part 2.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

I got interested in this when I read that you actually asked Chat GPT for solution. So I tried just a quick (pure force) Scheme (Racket) solution for the first (trebuchet) problem.

Code: Select all

``````#lang racket
(require racket/file)

(define (code-sum file)
(let ((lines
(map
(lambda (chr-lst) (map string chr-lst))
(map string->list (file->lines file #:mode 'text)))))
(apply + (map f+l lines (map reverse lines)))))

(define (f+l xl yl)
(let ((left (findf string->number xl))
(right (findf string->number yl)))
(cond
((and left right) (string->number (string-append left right)))
(left (string->number (string-append left left)))
(right (string->number (string-append right right)))
(else 0))))
``````
As you see just a few maps (inside maps) and two findf. This does not do anything with word numbers, but I dont think that Julia GPT program does either.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

This was too fast, and overly complicated.

Code: Select all

``````#lang racket
(require racket/file)

(define (code-sum file)
(let ((lines
(map
(lambda (chr-lst) (map string chr-lst))
(map string->list (file->lines file #:mode 'text)))))
(apply + (map f+l lines (map reverse lines)))))

(define (f+l xl yl)
(let ((left (findf string->number xl))
(right (findf string->number yl)))
(if left
(string->number (string-append left right))
0)))
``````

RogerW
Posts: 412
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

### Re: Advent of Code 2023

Did anyone else struggle with day 5 part 2? My code works on the test data and part 1 completes but part 2 takes forever. I know it is not hung but the very long ranges of seeds mean it would take hours if not days to complete. Clearly I am missing a shortcut but cannot see it. can anyone point me in the right direction.

Code: Select all

``````#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <list>
#include <tuple>
#include <limits>

const char* filename = "data.txt";

using param_type = unsigned;
using tup_type = std::tuple<param_type,param_type,param_type>;
using map_type = std::list<tup_type>;

std::list<param_type> seeds;
map_type maps[7];

bool sort_tuple(tup_type a, tup_type b)
{
return std::get<1>(a) < std::get<1>(b);
}

void fill_map(std::ifstream& file,map_type& map)
{
char buffer[100];
file.getline(buffer,sizeof(buffer));
while(true)
{
file.getline(buffer,sizeof(buffer));
if(buffer[0] < ' ')
break;

std::istringstream ss(buffer);
param_type i1,i2,i3;
ss >> i1 >> i2 >> i3;
map.push_back(std::make_tuple(i1,i2,i3));
}
map.sort(sort_tuple);
}

param_type find_location(param_type num,map_type map)
{
for(auto& entry : map)
{
param_type dest,src,len;
dest = std::get<0>(entry);
src = std::get<1>(entry);
len = std::get<2>(entry);

if(num >= src && num < src + len)
return dest + num - src;
}
return num;
}

int part1()
{
param_type ret = std::numeric_limits<param_type>::max();

for(auto s : seeds)
{
param_type num = s;
for(auto& m : maps)
num = find_location(num,m);

if(num < ret)
ret = num;
}

return ret;
}

param_type part2()
{
param_type ret = std::numeric_limits<param_type>::max();
auto i = seeds.begin();
while(i != seeds.end())
{
param_type start,end,x;
start = *i++;
end = start + *i++;
for(x = start; x < end ; x++)
{
param_type num = x;
for(auto& m : maps)
num = find_location(num,m);

if(num < ret)
ret = num;
}
}

return ret;
}

int main()
{
std::ifstream file(filename);
std::cout << "Advent of code 2023 day 5" << "\n";
if(file)
{
char buffer[300];
file.getline(buffer,sizeof(buffer));
std::istringstream ss(buffer);

// get rid of "seeds:"
std::string s;
ss >> s;

// get seeds
param_type i;
while(!ss.eof())
{
ss >> i;
seeds.push_back(i);
}

// skip blank line
file.getline(buffer,sizeof(buffer));

// get 7 maps
for(auto& map : maps)
fill_map(file,map);

std::cout << "Part1 " << part1() << "\n";
std::cout << "Part2 " << part2() << "\n";
}
else
std::cout << "No file\n";

return 0;
}
``````

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

RogerW wrote:
Sat Dec 09, 2023 11:38 am
Did anyone else struggle with day 5 part 2? My code works on the test data and part 1 completes but part 2 takes forever. I know it is not hung but the very long ranges of seeds mean it would take hours if not days to complete.
Indeed, day 5 part 2 requires a different approach. So, in theory the 1st item in a source range should translate to the least destination, but not all input ranges are fully contained within a translation range. You need to create new translated destination ranges for the parts that do not completely overlap. Do this 7 times, once for each translation table. The final set of destination ranges will contain the least destination. Having done this you should be able to calculate the solution in under 1 millisecond.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

Out of curiosity, I logged in to Advent and got my own "trebuchet" file. Actually the only thing I wanted to test is how long it will take Racket on rpi4b to get the answer. And the result is surprising. My correct result was 55816, but the time reported on rpi4 was 3ms (as in milliseconds)

My improved code (not lazy code like first two posts) is this:

Code: Select all

``````#lang racket
(require racket/file)

(define (code-sum file)
(let ((lines (map string->list (file->lines file #:mode 'text))))
(apply + (map f+l lines (map reverse lines)))))

(define (f+l ll rl)
(let ((left (findf char-numeric? ll))
(right (findf char-numeric? rl)))
(if left
(string->number (string left right))
0)))
``````
This is 65% faster than the previous code.

However I do not trust this result on rpi4 of 3ms. I think that the Racket time function resolution is too coarse, on such a short time intervals.
The same Racket code on my 10gen i5 reports 0ms, so that tells me nothing.
Anyway, I ported the code to Chez Scheme, which is a pain, because I had to implement file->lines, and findf functions myself.
From my previous experience Chez runs about 5x faster than Racket, and Chez reported 2.9354606ms.
That does not look OK with the racket result of 0, nor with the rpi4 result of 3. So to test properly, I placed the same test inside a do loop, and spun it 10000 times. That means that actually 10m lines are being processed.

This time Chez reports 4.155s, and Racket reports 8.71s. This is a more realistic result. Not 5x, but this is probably due to my implementations of the 2 key functions, which are built into the Racket. I did not try this on the rpi4.

RogerW
Posts: 412
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

### Re: Advent of Code 2023

lurk101 wrote:
Sat Dec 09, 2023 2:33 pm

Indeed, day 5 part 2 requires a different approach.
Thanks for the pointer. I am strill trying to work it out but will get there in the end.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

rpi4b manages day1 part 2 Racket code in 15-28ms. My i5 does the same in 3-4ms. So all in all this is a respectable result for pi.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

RPI4 & Racket code for day 2, part1 & part2
both parts are done in exactly the same time: 14ms each..

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

C++ run times, so far
Screenshot 2023-12-11 094123.png (90.41 KiB) Viewed 141309 times
Day 6 is incorrect and should read 0.079 ms. 0.081 ms. 0.08 ms. 0.17 ms.
Last edited by lurk101 on Mon Dec 11, 2023 3:09 pm, edited 1 time in total.

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

lurk101 wrote:
Mon Dec 11, 2023 2:43 pm
C++ run times, so far

Could the differences in timings between the Pi 5 and other Cortex-A76 systems be possibly due to different default option settings in the system compiler?

Edit: Fixed typo to clarify "option settings" in the above.
Last edited by ejolson on Mon Dec 11, 2023 5:10 pm, edited 1 time in total.

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

ejolson wrote:
Mon Dec 11, 2023 3:02 pm
Could the differences in timings between the Pi 5 and other Cortex-A76 systems be possibly due to different default opportunities settings in the system compiler?
Not sure what you mean by opportunities? Looking at the gcc code you find that the cortex-a72 and cortex a-76 use the same optimization profile for -O3. It is interesting that the Pi5 outperforms in most cases for single threaded applications. All use the same compiler version:

Code: Select all

``````pi@pi5:~/AoC-2023-cplusplus \$ gcc --version
gcc (GCC) 14.0.0 20231210 (experimental)
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
``````

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

lurk101 wrote:
Mon Dec 11, 2023 3:11 pm
ejolson wrote:
Mon Dec 11, 2023 3:02 pm
Could the differences in timings between the Pi 5 and other Cortex-A76 systems be possibly due to different default opportunities settings in the system compiler?
Not sure what you mean by opportunities? Looking at the gcc code you find that the cortex-a72 and cortex a-76 use the same optimization profile for -O3. It is interesting that the Pi5 outperforms in most cases for single threaded applications. All use the same compiler version:

Code: Select all

``````pi@pi5:~/AoC-2023-cplusplus \$ gcc --version
gcc (GCC) 14.0.0 20231210 (experimental)
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
``````
Sorry, my gesture typing failed. That was supposed to be options rather than opportunities. I'll edit the earlier post to make things more clear.

Some operating systems have differences in the defaults for position independent code and security mitigations like enabling the stack protector that could account for 7 to 10 percent. Is the assembler the same in both cases?
Last edited by ejolson on Tue Dec 12, 2023 12:51 am, edited 1 time in total.

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

ejolson wrote:
Fri Dec 08, 2023 9:21 pm
Note the second and third runs are about 80 times faster than the first.
Here my day 3 puzzle solution running on a Pi Zero at 700 MHz.

Code: Select all

``````julia> include("day03.jl")
Advent of Code 2023 Day 3 Gear Ratios

Part 1 The sum of the part numbers is 527446
Part 2 The sum of the gear ratios is 73201705

Total execution time 10.286119573 seconds.

julia> main()
Advent of Code 2023 Day 3 Gear Ratios

Part 1 The sum of the part numbers is 527446
Part 2 The sum of the gear ratios is 73201705

Total execution time 0.099547502 seconds.

julia> main()
Advent of Code 2023 Day 3 Gear Ratios

Part 1 The sum of the part numbers is 527446
Part 2 The sum of the gear ratios is 73201705

Total execution time 0.106823466 seconds.
``````
Again execution is significantly faster after just-in-time warmup.

The Julia code was

Code: Select all

``````#=  Advent of Code 2023 Day 3 Gear Ratios
Written 2023 by Eric Olson =#

struct DoExit <: Exception
end

function issymbol(c::Char)::Bool
if isdigit(c)||c=='.'
return false
end
return true
end

function getpart(s::String)::Tuple{Int,Int}
n=0
for i=1:length(s)
if s[i]>='0'&&s[i]<='9'
n=n*10+(s[i]-'0')
else
return i-1,n
end
end
return length(s),n
end

function mksearch(data)
m=length(data)
n=length(data[1])
z=zeros(Int8,m,n)
function hflood(i::Int,j::Int)
if i<1||i>m||j<1||j>n
return 0
end
if !isdigit(data[i][j])||z[i,j]>0
return 0
end
z[i,j]=1
hflood(i,j-1); hflood(i,j+1)
return 1
end
function asearch(i::Int,j::Int)
if data[i][j]=='.'||z[i,j]>0
return
end
z[i,j]=hflood(i-1,j-1)+hflood(i-1,j)+hflood(i-1,j+1)+
hflood(i,j-1)+                hflood(i,j+1)+
hflood(i+1,j-1)+hflood(i+1,j)+hflood(i+1,j+1)
end
return asearch
end

function part1(data,asearch)
m=length(data)
n=length(data[1])
z=asearch.z
for i=1:m,j=1:n
if issymbol(data[i][j]) asearch(i,j) end
end
s=0
for i=1:m
j=1
while j<=n
if isdigit(data[i][j])&&z[i,j]>0
δ,k=getpart(data[i][j:end])
s+=k; j+=δ
else
j+=1
end
end
end
return s
end

function part2(data,asearch)
m=length(data)
n=length(data[1])
z=asearch.z
function getgear(i::Int,j::Int)::Int
if !isdigit(data[i][j])||z[i,j]==0
return 1
end
while j>1
j-=1
if !isdigit(data[i][j])||z[i,j]==0
j+=1; break
end
end
_,k=getpart(data[i][j:end])
while j<=m&&isdigit(data[i][j])
z[i,j]=0
j+=1
end
return k
end
function getratio(i::Int,j::Int)
return getgear(i-1,j-1)*getgear(i-1,j)*getgear(i-1,j+1)*
getgear(i,j-1)*                 getgear(i,j+1)*
getgear(i+1,j-1)*getgear(i+1,j)*getgear(i+1,j+1)
end
s=0
for i=1:m, j=1:n
if data[i][j]=='*'&&z[i,j]==2
r=getratio(i,j)
z[i,j]=0
asearch(i,j)
s+=r
end
end
return s
end

function doinit()
data=[]
open("day03.txt","r") do fp
end
asearch=mksearch(data)
p1=part1(data,asearch)
p2=part2(data,asearch)
println("Part 1 The sum of the part numbers is ",p1)
println("Part 2 The sum of the gear ratios is ",p2)
end

function main()
t=@elapsed try
println("Advent of Code 2023 Day 3 Gear Ratios\n")
doinit()
throw(DoExit())
catch r
if !isa(r,DoExit)
rethrow(r)
end
end
println("\nTotal execution time ",t," seconds.")
end

main()
``````
The closures look clumsy to me but Fido's tail is wagging. That means there is no need to worry about how the enclosed z array gets referenced as asearch.z later in the code.

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

ejolson wrote:
Mon Dec 11, 2023 5:09 pm
Some operating systems have differences in the defaults for position independent code and security mitigations like enabling the stack protector that could account for 7 to 10 percent.
Not sure.
Pi5

Code: Select all

``````Vulnerabilities:
Gather data sampling:  Not affected
Itlb multihit:         Not affected
L1tf:                  Not affected
Mds:                   Not affected
Meltdown:              Not affected
Mmio stale data:       Not affected
Retbleed:              Not affected
Spec rstack overflow:  Not affected
Spec store bypass:     Not affected
Spectre v1:            Mitigation; __user pointer sanitization
Spectre v2:            Mitigation; CSV2, but not BHB
Srbds:                 Not affected
Tsx async abort:       Not affected
``````
rock 5b

Code: Select all

``````Vulnerabilities:
Itlb multihit:        Not affected
L1tf:                 Not affected
Mds:                  Not affected
Meltdown:             Not affected
Mmio stale data:      Not affected
Retbleed:             Not affected
Spec store bypass:    Not affected
Spectre v1:           Mitigation; __user pointer sanitization
Spectre v2:           Mitigation; CSV2, but not BHB
Srbds:                Not affected
Tsx async abort:      Not affected
``````
orange pi 5

Code: Select all

``````Vulnerabilities:
Itlb multihit:        Not affected
L1tf:                 Not affected
Mds:                  Not affected
Meltdown:             Not affected
Mmio stale data:      Not affected
Retbleed:             Not affected
Spec store bypass:    Not affected
Spectre v1:           Mitigation; __user pointer sanitization
Spectre v2:           Mitigation; CSV2, but not BHB
Srbds:                Not affected
Tsx async abort:      Not affected
``````
Vulnerabilities all look the same, but the pi 5 is running 6.1 kernels whereas the rockchip are running 5.10.
Is the assembler the same in both cases?
I imagine the same, but I'd have to look at the disassembled code and that's too much work.

bensimmo
Posts: 6830
Joined: Sun Dec 28, 2014 3:02 pm
Location: East Yorkshire

### Re: Advent of Code 2023

You could try the 6.6 Pi kernel that's in testing. (next)

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

lurk101 wrote:
Mon Dec 11, 2023 5:28 pm
ejolson wrote:
Mon Dec 11, 2023 5:09 pm
Is the assembler the same in both cases?
I imagine the same, but I'd have to look at the disassembled code and that's too much work.
Is it possible to copy the binaries between systems and have them run?

Here is a comparision of the compile and run cycles for the C++ code

https://raw.githubusercontent.com/lurk1 ... /day03.cpp

to just-in-time compiled Julia.

After creating the file candr as

Code: Select all

``````#!/bin/bash
g++ -O3 -o day03 day03.cpp
exec ./day03 "\$@"
``````
running on a Pi 4B at 1500 MHz obtained

Code: Select all

``````\$ time ./candr
--- Day 3: Gear Ratios ---
Part 1  - 527446
Part 2  - 73201705
Elapsed - 0.917 ms.

real    0m2.835s
user    0m2.593s
sys 0m0.243s
\$ time julia day03.jl
Advent of Code 2023 Day 3 Gear Ratios

Part 1 The sum of the part numbers is 527446
Part 2 The sum of the gear ratios is 73201705

Total execution time 0.826625262 seconds.

real    0m2.270s
user    0m2.190s
sys 0m0.312s
``````
It's possible the algorithms are different, but even so, the execution times are similar.

More detailed results are available with perf.

Code: Select all

``````\$ perf stat ./candr
--- Day 3: Gear Ratios ---
Part 1  - 527446
Part 2  - 73201705
Elapsed - 0.841 ms.

Performance counter stats for './candr':

2,848.80 msec task-clock:u                     #    1.000 CPUs utilized
0      context-switches:u               #    0.000 /sec
0      cpu-migrations:u                 #    0.000 /sec
23,894      page-faults:u                    #    8.387 K/sec
3,830,683,708      cycles:u                         #    1.345 GHz
2,456,487,129      instructions:u                   #    0.64  insn per cycle
<not supported>      branches:u
31,405,076      branch-misses:u

2.849971583 seconds time elapsed

2.591639000 seconds user
0.258528000 seconds sys
``````
and

Code: Select all

``````\$ perf stat julia day03.jl
Advent of Code 2023 Day 3 Gear Ratios

Part 1 The sum of the part numbers is 527446
Part 2 The sum of the gear ratios is 73201705

Total execution time 0.821978366 seconds.

Performance counter stats for 'julia day03.jl':

2,512.55 msec task-clock:u                     #    1.093 CPUs utilized
0      context-switches:u               #    0.000 /sec
0      cpu-migrations:u                 #    0.000 /sec
39,008      page-faults:u                    #   15.525 K/sec
3,229,749,954      cycles:u                         #    1.285 GHz
2,402,085,759      instructions:u                   #    0.74  insn per cycle
<not supported>      branches:u
21,582,696      branch-misses:u

2.299270463 seconds time elapsed

2.188206000 seconds user
0.324624000 seconds sys
``````
The C++ compile and run cycle took 2,456,487,129 instructions while Julia took 2,402,085,759 which is a similar number.

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

Ah, it seems g++ was using a generic optimization profile and not detecting the actual processor. By forcing the A76 profile with -mtune=cortex-a76 I get slightly improved run times, but Pi5 still outperforms.

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

lurk101 wrote:
Mon Dec 11, 2023 7:05 pm
Ah, it seems g++ was using a generic optimization profile and not detecting the actual processor. By forcing the A76 profile with -mtune=cortex-a76 I get slightly improved run times, but Pi5 still outperforms.
I wonder if explicitly specifying Cortex-A76 tuning would have an effect on the Pi Chart calculations.

viewtopic.php?p=2147572#p2147572

Here is a solution for day 4 running on the Pi Zero:

Code: Select all

``````julia> include("day04.jl")
Advent of Code 2023 Day 4 Scratchcards

Part 1 The total number of points is 17803
Part 2 The total scratchcards at the end is 5554894

Total execution time 7.118361389 seconds.

julia> main()
Advent of Code 2023 Day 4 Scratchcards

Part 1 The total number of points is 17803
Part 2 The total scratchcards at the end is 5554894

Total execution time 0.183153032 seconds.

julia> main()
Advent of Code 2023 Day 4 Scratchcards

Part 1 The total number of points is 17803
Part 2 The total scratchcards at the end is 5554894

Total execution time 0.181672041 seconds.
``````
I'm pretty impressed the dog developer's ARMv6 port of Julia is managing to run these Julia programs at all. The warm-up-time is slow but performance after that is fine.

For reference the code is

Code: Select all

``````#=  Advent of Code 2023 Day 4 Scratchcards
Written 2023 by Eric Olson =#

struct DoExit <: Exception
end

function gobble(s::String,m::String)::Tuple{String,Bool}
if length(s)<length(m)
return s,false
end
if s[1:length(m)]==m
return s[length(m)+1:end],true
end
return s,false
end

function wskip(s::String)::String
for i=1:length(s)
if !isspace(s[i])
return s[i:end]
end
end
return ""
end

function getint(s::String)::Tuple{String,Int}
n=0
for i=1:length(s)
if s[i]>='0'&&s[i]<='9'
n=n*10+(s[i]-'0')
else
return s[i:end],n
end
end
return "",n
end

function getlist(s::String)::Tuple{String,Vector{Int}}
u=Int[]
while length(s)>0
if begin s,x=getint(s); x==0 end
return s,u
end
s=wskip(s)
push!(u,x)
end
return "",u
end

mutable struct cardspec
n::Int
w::Vector{Int}
v::Vector{Int}
end

function getcard(s::String)::cardspec
r=s
if begin s,f=gobble(s,"Card"); !f end
println("%r\nDid not begin with Card!")
throw(DoExit())
end
s=wskip(s)
if begin s,n=getint(s); n==0 end
println("\$r\nCould not parse card number!")
throw(DoExit())
end
if begin s,f=gobble(s,":"); !f end
println("%r\nMissing : separator!")
throw(DoExit())
end
s=wskip(s)
if begin s,w=getlist(s); length(w)==0 end
println("\$r\nCould not parse winning numbers!")
throw(DoExit())
end
if begin s,f=gobble(s,"|"); !f end
println("%r\nMissing | separator!")
throw(DoExit())
end
s=wskip(s)
if begin s,v=getlist(s); length(v)==0 end
println("\$r\nCould not parse my numbers!")
throw(DoExit())
end
return cardspec(n,sort(w),sort(v))
end

function getmatches(c::cardspec)::Int
i=1; j=1; r=0
while i<=length(c.w)&&j<=length(c.v)
if c.w[i]<c.v[j]
i+=1
elseif c.w[i]>c.v[j]
j+=1
else
r+=1
i+=1
j+=1
end
end
return r
end

function getvalue(c::cardspec)::Int
r=getmatches(c)
if r==0
return 0
else
return 2^(r-1)
end
end

function part1(data)::Int
s=0
for i=1:length(data)
c=getcard(data[i])
s+=getvalue(c)
end
return s
end

function part2(data)::Int
m=ones(Int,length(data))
s=0
for i=1:length(data)
c=getcard(data[i])
r=getmatches(c)
for j=i+1:i+r
m[j]+=m[i]
end
end
return sum(m)
end

function doinit()
data=[]
open("day04.txt","r") do fp
end
p1=part1(data)
p2=part2(data)
println("Part 1 The total number of points is ",p1)
println("Part 2 The total scratchcards at the end is ",p2)
end

function main()
t=@elapsed try
println("Advent of Code 2023 Day 4 Scratchcards\n")
doinit()
throw(DoExit())
catch r
if !isa(r,DoExit)
rethrow(r)
end
end
println("\nTotal execution time ",t," seconds.")
end

main()
``````
Except for the mutable structure there was nothing new. The day 4 puzzle seemed easier than day 3.

lurk101
Posts: 2558
Joined: Mon Jan 27, 2020 2:35 pm
Location: Cumming, GA (US)

### Re: Advent of Code 2023

ejolson wrote:
Mon Dec 11, 2023 9:57 pm
The day 4 puzzle seemed easier than day 3.
They all seemed pretty easy, till I hit day 5 part 2!

ejolson
Posts: 12171
Joined: Tue Mar 18, 2014 11:47 am

### Re: Advent of Code 2023

lurk101 wrote:
Tue Dec 12, 2023 12:58 am
ejolson wrote:
Mon Dec 11, 2023 9:57 pm
The day 4 puzzle seemed easier than day 3.
They all seemed pretty easy, till I hit day 5 part 2!
I just got to day 5 part 2. The code is stuck in a loop and the dog developer has already gone to sleep. That makes it difficult to delegate part 2. I think I'll go to sleep as well.

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

Day 3: Racket on rpi4b

part 1: 15ms (best)
part 2: 11ms (best)

(This "best" simply means that GC did not kick in that run)

hrvoje064
Posts: 50
Joined: Fri Sep 09, 2022 4:08 am

### Re: Advent of Code 2023

Day 4: Racket on rpi4b

Part 1: 30ms (best)
Part 2: 30ms (best)

Re: speed, (or lack of it), I should explain that in both parts of day 4, unlike day 3 - where I had to use vectors, here I used only lists. With some list surgery in part 2.