working on another fractal animation, this time a julia morph orbiting in the hairs of an island. no clue yet if it will turn out any good...

current progress:
- found the angled internal address for one exemplar by tracing a ray outwards in mandelbrot-perturbator-gtk
- found a pattern for the external angles of the prefix, by tracing a few more rays outwards (much shallower) and comparing the binary strings
- wrote some haskell to combine the prefixes with the suffix of the examplar address, and compute one of the corresponding external angle pairs
- now tracing the rays to end-points in parallel:

```
cat rays.txt | parallel -k m-exray-in 100 "{}" 8 $((2 * 8 * 1378)) | tee -a endpoints.txt
```

- a total of 256 rays on 16 threads, ETA about 1h30 wall-clock (plus the 20mins done already)

...and results are in: it doesn't work as an animation at all, frames are seemingly unconnected. I guess pasting a different prefix onto an angled internal address does not do anything useful structurally, even though it happened to give valid addresses in this instance.

Show thread

The first 3 prefixes were 1 1/2 2 1/2 3 followed by:

- 1/10 28
- 1/8 24 1/2 28
- 1/7 21 1/2 28

where the first is what I designed, and the other 2 are extrapolated. I think the change of /10 to /8 and /7 messed up the structural assumptions of the suffix, which was

1/2 56 1/2 57 1/2 58 1/3 144 1/2 145 1/2 146 1/3 320 ... 1378

In particular the influencing island had period 3 and the influencing angle was n/10, so 3*10=30 aligned nicely with the repeated structure of p->2p+30 in the angled internal addresses; while the non-n/10 addresses are forced/unrelated so don't look as good...

Show thread
Follow

The structure of the first frame was created by going one step along into one of the neighbouring double spirals; if the angle is n/10 this affects the period by p->2p+30. If the angle is say n/8, I suspect the period would change by p->2p+24; for angle n/7 by p->2p+21, etc. So maybe I can rescue this animation concept after all:

0. calculate external angle of prefix as .({011,100}^8 0111) (256 locations)
1. calculate angled internal address of prefix from external angle of prefix
2. extract the angle at 1 1/2 2 1/2 3 n/q
3. build the suffix by repetitions of (p-2) 1/2 (p-1) 1/2 p 1/3 2p+3q-2 1/2 2p+3q-1 1/2 2p+3q 1/3 ...

Not sure if this will be sufficient, as some of the hairs come off grandchild bulbs with more than one non-1/2 angle..

· · Web · 2 · 0 · 0

Haskell implementation of previous toot:
```
main = writeFile "rays.txt" . unlines . map (\prefix ->
let Just addressPrefix@(Sym.Angled 1 _ (Sym.Angled 2 _ (Sym.Angled 3 pq _))) = (Sym.angledAddress . Sym.rational) =<< Txt.parse prefix
addressSuffix (Sym.Angled p t a) = Sym.Angled p t (addressSuffix a)
addressSuffix (Sym.Unangled p) = Sym.Angled p (1 Sym.% 2) (go 4 (2 * p))
where
go 0 p = Sym.Angled p (1 Sym.% 2) (Sym.Angled (p + 1) (1 Sym.% 2) (Sym.Unangled (p + 2)))
go n p = Sym.Angled p (1 Sym.% 2) (Sym.Angled (p + 1) (1 Sym.% 2) (Sym.Angled (p + 2) (1 Sym.% 3) (go (n - 1) (2 * (p + 2) + m - 2))))
m = 3 * fromIntegral (Sym.denominator pq)
address = addressSuffix addressPrefix
Just ray = Txt.plain . Sym.binary . fst <$> Sym.addressAngles address
in ray) $ prefixes
where
lo = "011"
hi = "100"
prefixes = (".(" ++) . (++ "0111)") . concat <$> replicateM 8 [lo, hi]
```

Show thread

Bash script to trace all the rays (they have different periods now which complicates things, optimal ray tracing depth generally depends on period; next stage after this will be Newton's method to find the center and that explicitly needs the period):
```
cat rays.txt |
while read ray
do
period=$(( $(echo "$ray" | wc -c) - 4 ))
echo m-exray-in 100 "'${ray}'" 8 "$((2 * 8 * $period))"
done |
parallel -k |
tee -a endpoints.txt
```
note double and single quotes around ${ray}, otherwise the () in the string are interpreted by bash -c within parallel and that breaks everything (syntax error)

Show thread

It wasn't the grandchild-bulbs causing issues, it was naivety that the address patterns would be so simple. Suppose the address starts:

1 2 3 p/q ... 28 ...

If 3q > 28, then the first ... is empty, but if 3q < 28 then 3q appears in the address. When 3q is not in the address (the case I started with, turns out to be rare) then the address pattern is as described above.

When 3q is in the address it's much simpler: after the 28 comes 1/2 28+3q, then after that the pattern is ... p 1/3 2p+3q 1/3 ...

I think. I need to actually render all the corresponding images to check that it is correct...

Show thread

Haskell code corresponding to description above:

```
main = writeFile "rays.txt" . unlines . map (\prefix ->
let Just addressPrefix@(Sym.Angled 1 _ (Sym.Angled 2 _ (Sym.Angled 3 pq _))) = (Sym.angledAddress . Sym.rational) =<< Txt.parse prefix
addressSuffix (Sym.Angled p t a) = Sym.Angled p t (addressSuffix a)
addressSuffix (Sym.Unangled p) = Sym.Angled p (1 Sym.% 2) (go 4 p0)
where
p0 | m < 28 = 28 + m
| m > 28 = 2 * p
go 0 p | m < 28 = Sym.Unangled p
go n p | m < 28 = Sym.Angled p (1 Sym.% 3) (go (n - 1) (2 * p + m))
go 0 p | m > 28 = Sym.Angled p (1 Sym.% 2) (Sym.Angled (p + 1) (1 Sym.% 2) (Sym.Unangled (p + 2)))
go n p | m > 28 = Sym.Angled p (1 Sym.% 2) (Sym.Angled (p + 1) (1 Sym.% 2) (Sym.Angled (p + 2) (1 Sym.% 3) (go (n - 1) (2 * (p + 2) + m - 2))))
m = 3 * fromIntegral (Sym.denominator pq)
address = addressSuffix addressPrefix
Just ray = Txt.plain . Sym.binary . fst <$> Sym.addressAngles address
in ray) $ prefixes
where
lo = "011"
hi = "100"
prefixes = (".(" ++) . (++ "0111)") . concat <$> replicateM 8 [lo, hi]
```

Show thread

Nice, this works.

The alignment code needs to be adjusted. For an address with patterns ending ... M 1/3 ... N, the nodes to align with have period M+N. So I'll extend the Haskell code to dump that out too, then import it in a small C program to do the aligning. Good viewport zoom factor was 2 / (10 * atom domain size ** 1.125), this will be tweaked and rotated so the alignment nodes are fixed in screenspace.

Animation may end up a bit stroboscopic all the same, as branching order changes quite often.

Show thread

quite pleased with parts of this, though when the number of branches jumps a few times in quick succession it's a bit annoying. maybe i can ping-pong some of the longer sections (corresponding to the 1/3, 1/2, 2/3 child bulbs)

Show thread

`paste` is my new favourite command line tool, along with `parallel -k`. Here I use it to add columns to a table. It's annoying that you can't replace the file you're reading from all in one operation, but I suppose it's good to have copies in case of a crash or power failure etc.

```
#!/bin/bash
prec=1000
cat a.txt | while read ray period node ; do echo "m-exray-in 100 '${ray}' 8 $((2 * 8 * ${period}))" ; done | parallel -k | paste a.txt - | tee b.txt
cat b.txt | while read ray period node re im ; do echo m-nucleus $prec $re $im $period 64 1 ; done | parallel -k | paste b.txt - | tee c.txt
cat c.txt | while read ray period node ere eim nre nim; do echo m-domain-size $prec $nre $nim $period ; done | parallel -k | paste c.txt - | tee d.txt
cat d.txt | while read ray period node ere eim nre nim ds ; do echo $ds ; done | ghc -e "interact $ unlines . map (show . (\s -> 2 / (10 * s**1.125)) . read) . lines" | paste d.txt - | tee e.txt
cat -n e.txt | while read n ray period node ere eim nre nim ds zoom ; do echo -e "Re: $nre\r\nIm: $nim\r\nZoom: $zoom\r" | m-align-nodes ${node} > $(printf %04d.kfr $n) ; done
for i in ????.kfr ; do kf.x86_64.exe -s settings.kfs -l "$i" -c palette.kfp -t "$i.tif" 2>&1 | grep -v fix ; done
```

Show thread

I added motion blur as suggested by lycium in the fractal chats discord, not sure if I like it (I think 8 subframes is not enough to avoid steppy appearance, and rendering 8x as many frames takes 8x as long, it took 3 hours to render 1024 images for this 128 frame output, not counting the time taken to trace the rays to the locations etc).

Show thread

@mathr very interesting. is there any way to slow down the process (interpolate more finely)? what does "jumps between structurally related locations" mean - are there more intermediate locations?

@sciss mathr.co.uk/blog/2013-06-23_pa has some diagrams, I attached one here. Essentially there are no more intermediate locations, but there is a related family with twice the number of locations, and this extends to a family of families with 2^N members where N gets arbitrarily high.

The number of branches in the bushes depends on the first disc passed through, you can see the big circle on the left has 2 branches, while the next-biggest at top and bottom have 3 branches. Between a pair of "neighbouring" P and Q branched discs is a P+Q branched disc. Here neighbouring is in the sense of "no bigger (smaller period) disc is between them".

As you can see, there are an infinite number of disks with smaller disks between them, so as you increase the density in the hairs the jumps between smoother bulb video sections become more jumps and shorter smooth bulb video sections. It has a fractal structure.

"Structurally related" means the process for arriving at each frame is very similar. Here the process was: for each odd-index hair at depth N+1 (here N = 10 for 1024 frames), find the lowest period island in the hair, zoom to its embedded Julia set, then zoom in one notch into one of the double spirals near the center, and repeat this process a few times to create the tree structure.

visualizing the ray angles in binary gives some weird patterns.

working on a soundtrack now.

C code 

// gcc a.c -lsndfile -lfftw3 -lm
<complex.h>
<math.h>
<stdbool.h>
<stdio.h>
<stdlib.h>
<string.h>
<sndfile.h>
<fftw3.h>
typedef double R;typedef double _Complex C;int main(int m, char **z){const int S=192000;const int F=60;const int N=S/F;float a[N][2];C*i=fftw_malloc(N*sizeof(*i));C*j=fftw_malloc(N*sizeof(*j));fftw_plan k=fftw_plan_dft_1d(N,i,j,FFTW_BACKWARD,FFTW_PATIENT|FFTW_DESTROY_INPUT);int Q=0;C*f=0;C*g=0;fftw_plan h=0;SF_INFO o={0,S,2,SF_FORMAT_WAV|SF_FORMAT_FLOAT,0,0};SNDFILE*O=sf_open("a.wav",SFM_WRITE,&o);while(1){int P=0;char*r[2]={0,0};if(3!=scanf("%d\t%ms\t%ms\n",&P,&r[0],&r[1]))break;if(P!=Q){if(f)fftw_free(f);if(g)fftw_free(g);if(h)fftw_destroy_plan(h);f=fftw_malloc(P*sizeof(*f));g=fftw_malloc(P*sizeof(*g));h=fftw_plan_dft_1d(P,f,g,FFTW_FORWARD,FFTW_MEASURE|FFTW_DESTROY_INPUT);}for(int c=0;c<2;++c){int v=0;for(int p=0;p<P;++p){f[p]=v;v+=r[c][p]=='0'?-1:1;}free(r[c]);R s=v/(R)P;C d=0;for(int p=0;p<P;++p)d+=(f[p]-=p*s);d/=P;for(int p=0;p<P;++p)f[p]-=d;fftw_execute(h);memset(i,0,N*sizeof(*i));for(int p=0;p<P/2;++p){i[p]=g[p];i[N-1-p]=g[P-1-p];}fftw_execute(k);s=0;for(int p=0;p<N;++p){a[p][c]=creal(j[p]);s+=a[p][c]*a[p][c];}s=0.25/sqrt(s/N);for(int p=0;p<N;++p)a[p][c]*=s;}sf_writef_float(O,&a[0][0],N);Q=P;}sf_close(O);return 0;}

Sign in to participate in the conversation
post.lurk.org

Welcome to post.lurk.org, an instance for discussions around cultural freedom, experimental, new media art, net and computational culture, and things like that.