Do is not ¨returning¨ array (campanology)

do doesn’t return, you need to just write data at the end of the function to get it out, but there is no function because that requires curly braces.

Also, and I’m not too sure this is what you want because your code is hard to read, but is your intention just to reverse the array?

5.collect({|i| i}).reverse;
\\ or
Array.iota(5).reverse;

obviously, the code needs clarity.
I tried to make a function in order to return an array, and I find a weird behavior.
See for yourself:

(
~reflection = {
	|parts|
	var data;
	var change1;
	var change2;
	var result;

	data = (0..parts-1);
	data.postln;
	result=[data];
	change1 = (data.size/2).asInteger;
	change2 = if(parts.odd, {change1}, {change1-1});
	parts.do{
		|count|
		var item=result.last;
		if (count.even)
		{change1.do{|i| item=item.swap(i*2, i*2+1)}}
		{change2.do{|i| item=item.swap(i*2+1, i*2+2)}};
		result=result.add(item.postln)
	};
	result
};
)

~reflection.(5)

Right, got ya!
Supercollider (confusingly) has object semantics rather than value, this means …

var x = y

Is actually saying, “from now on I shall refer to y as x”, as oppose to
“let there be some value x who has the value y holds”.
A subtle and very important difference.
This fixes the problem. I’m gonna have a think if there is a better way to do this. Essentially using methods like add or even using mutable variables will always raise these sorts of problems.

(
~reflection = {
	|parts|
	var data;
	var change1;
	var change2;
	var result;

	data = (0..parts-1);
	data.postln;
	result=[data];
	change1 = (data.size/2).asInteger;
	change2 = if(parts.odd, {change1}, {change1-1});
	parts.do{
		|count|
		var item = result.last.copy; // here you want to make a copy!!
		if (count.even)
		{change1.do{|i| item=item.swap(i*2, i*2+1)}}
		{change2.do{|i| item=item.swap(i*2+1, i*2+2)}};
		result=result.add(item)
	};
	result
};
)
1 Like

got ya too! very subtle indeed.

I’d suggest doing this with .collect rather than .do !

You can remove the need for all mutable variables by computing the indexes to swap first - these are stored in indexesEven and indexesOdd.
Then an array of functions is made (swappers)…i.e.[indexesEven, indexesOdd, indexesEven....]
Finally, .inject is used to chain these together, taking the previous result as the input to the next and building an array.

(
~swap_sort_steps  = {
	|parts|
	var swapConsequtiveIndexes = {|from, to|  
		(from..to).clump(2).collect{|p| p.reverse }.flat 
	};
	var indexesEven = swapConsequtiveIndexes.(0, parts - 1);  
	var indexesOdd = [0] ++ swapConsequtiveIndexes.(1, parts - 1);  
	var swappers = parts.collect{ |n|
		{|toSwap| if(n.even) 
			{ indexesEven.collect{|i| toSwap[i]} }  
			{ indexesOdd.collect{|i|  toSwap[i]} }   
		}
	};
	postf("indexesEven : %\nindexesOdd : %\n", indexesEven, indexesOdd);
	swappers.inject( [(0..parts-1)], {
		|col, f|
		col ++ [f.(col.last)]
	});
};
)

Also, as I’m sure you know, if anyone else is reading who doesn’t know what this is… its a swap sort algorithm.

Thanks Yann, this was helpful. With those adjustments I’m now getting what I expected from the final line of code “data.postln;”

do doesn’t return, you need to just write data at the end of the function to get it out, but there is no function because that requires curly braces.

Sorry for basic question, but where exactly should the “data” go? I’m also now a bit confused as with the edits suggested by Yann, the code is now working as I hoped. In my mind the “data” is being returned from the do.

Also, and I’m not too sure this is what you want because your code is hard to read, but is your intention just to reverse the array?

To reverse the array yes, but as a process. So there can be gradients of ´reversal´.

I will take a closer look at the function you created Yann, although it returns nothing for at the moment.

Thank you both for your inputs, greatly appreciated.

do is used to do something, it returns the object…

5.do{...} // this will return the number 5 regardless of whats inside the curlies

This solution works as I think you would expect… just remove the postf line.

I wonder where did you find this `transformation/reflection’ algorithm?
I would like to add it to the extension cycle (and incidentally cl-cycle) with reference(s) if so.
Thanks

I believe, its a variant on the bubble sort algorithm.

Except that I want to implement it with any kind of array:

(
~reflection = {
	|data|
	var change1, change2, result;
	result=[data];
	change1 = (data.size/2).asInteger;
	change2 = if(data.size.odd, {change1}, {change1-1});
	data.size.do{
		|count|
		var item=result.last.copy;
		if (count.even)
		{change1.do{|i| item=item.swap(i*2, i*2+1)}}
		{change2.do{|i| item=item.swap(i*2+1, i*2+2)}};
		result=result.add(item)
	};
	result
};
)

Is that still a swap sort algorithm? Is there any reference(s) as an article or else?

What do you mean with any kind? I altered it to take any collection rather than a number, is this what you meant?

(
~swap_sort_steps  = {
	|collection|
	var size = collection.size;
	var swapConsequtiveIndexes = {|from, to|  
		(from..to).clump(2).collect{|p| p.reverse }.flat 
	};
	var indexesEven = swapConsequtiveIndexes.(0, size - 1);  
	var indexesOdd = [0] ++ swapConsequtiveIndexes.(1, size - 1);  
	var swappers = size.collect{ |n|
		{|toSwap| if(n.even) 
			{ indexesEven.collect{|i| toSwap[i]} }  
			{ indexesOdd.collect{|i|  toSwap[i]} }   
		}
	};
	swappers.inject( [collection], {
		|col, f|
		col ++ [f.(col.last)]
	});
};
)

~swap_sort_steps.(['a', 'b', 'c', 'd']) 
//returns  [ [ a, b, c, d ], [ b, a, d, c ], [ b, d, a, c ], [ d, b, c, a ], [ d, c, b, a ] ]

Hi Yann,

It is something I developed that’s influenced by a study of change ringing / campanology. Unlike campanology however the goal is not to ring as many permutations as possible but to reflect a pattern via a process.

I don’t see it as a variation of a bubble sort algorithm since rather than sorting the data by analysis it is simply reflecting it via a process, just as a mirror reflects light without any knowledge or concern for the nature of the object being reflected.

I also perceive something aesthetic and beautiful within this particular algorithm in that the number of changes it takes to reverse the array is equal to the length of the array, providing a sense of steadiness to the gradual process of reversal, that operates irrespective of whether elements are traveling far, as in the case of those on the outer edges, or near, as in those closer to the centre.

So sorry for the basic question, but if I wanted to see the entire output of such a function, rather than just a preview with an “…etc…”, how would I do that?

In other words, using more variable, and running the swap_sort_steps… i only get:

“-> [ [ a, b, c, d, e, f, g, h, i, j, k, l, m ], [ b, a, d, c, f, e, h, g, j, i, l, k, m ], [ b, d, a, f, c, h, e, j, g, l, i, m, k ], [ d, b, f, a, h, c, j, e, l, g, m, i, k ], [ d, f, b, h, a, j, c, l, e, m, g, k, i ], [ f, d, h, b, j, a, l, c, m, e, k, g, i ], [ f, h, d, j, b, l, a, m, c, k, e, i, g ], [ h, f, j, d, l, b, m, a, k, c, i, e, g ], [ h, j, f, l, d, m, b, k, a, i, c, g, e ], [ j, h, l, f, m, d, k, b, i, a, g, c, e ], [ j, l, h, m, f, k, d, i, b, g, a, e, c ], [ l, j, m, h, k, f, i, d, g, b, e, a,…etc…”

How would I be able to see a list of all iterations?

some_array.do(_.postln)

posting each item separately is often easiest.

1 Like

Hey guys, how hard would it be to take this beautiful campanology script and to modify it so as to incorporate a hunting bell?

(if the image isn’t loading, see https://www.treblesgoing.org.uk/plainhuntjohnheaton.html for a simple explanation.)

@Reiny has done change ringing stuff, but I don’t know if they ever did it in SC or if they are very present around here right now.

Sam

1 Like

Hi,
If I understand, it is a question of timing and/or gesture constraints. Can you be more specific about the goal of this ‘script’? On this thread, we solved what you call the ‘Plain Hunt’ using cycle quarks : (1..5).campanology(1)
What kind of ‘extra’ parameter would make sense according to your document?
Sorry in advance if I misunderstood your point.

1 Like

First off, oh my gosh I’m so sorry for not realizing that! That’s great.

How how hard would it be to take the basic Plaint Hunt script and modify it to produce it’s more complex cousin, Plain Bob? There seems to me only one crucial difference that would need to be implemented to create this more complex pattern from the existing script, which is the “first pair stays, rest swaps” aspect:

Plain Bob:

[ 1, 2, 3, 4, 5, 6 ] - starts off like Plain Hunt i.e. “[ 1, 2, 3, 4, 5, 6 ].campanology(1);”
[ 2, 1, 4, 3, 6, 5 ]
[ 2, 4, 1, 6, 3, 5 ]
[ 4, 2, 6, 1, 5, 3 ]
[ 4, 6, 2, 5, 1, 3 ]
[ 6, 4, 5, 2, 3, 1 ]
[ 6, 5, 4, 3, 2, 1 ]
[ 5, 6, 3, 4, 1, 2 ]
[ 5, 3, 6, 1, 4, 2 ]
[ 3, 5, 1, 6, 2, 4 ]
[ 3, 1, 5, 2, 6, 4 ]
[ 1, 3, 2, 5, 4, 6 ] - where the current Plain Hunt script ends

[ 1, 3, 5, 2, 6, 4 ] - first pair stays, rest swap, then “[ 1, 3, 5, 2, 6, 4 ].campanology(1);”
[ 3, 2, 1, 4, 5, 6 ]
[ 2, 3, 4, 1, 6, 5 ]
[ 2, 4, 3, 6, 1, 5 ]
[ 4, 2, 6, 3, 5, 1 ]
[ 4, 6, 2, 5, 3, 1 ]
[ 6, 4, 5, 2, 1, 3 ]
[ 6, 5, 4, 1, 2, 3 ]
[ 5, 6, 1, 4, 3, 2 ]
[ 5, 1, 6, 3, 4, 2 ]
[ 1, 5, 3, 6, 2, 4 ]

[ 1, 5, 6, 3, 4, 2 ] - first pair stays, rest swap, then “[ 1, 5, 3, 6, 2, 4 ].campanology(1);”
[ 5, 1, 3, 6, 2, 4 ]
[ 5, 3, 1, 2, 6, 4 ]
[ 3, 5, 2, 1, 4, 6 ]
[ 3, 2, 5, 4, 1, 6 ]
[ 2, 3, 4, 5, 6, 1 ]
[ 2, 4, 3, 6, 5, 1 ]
[ 4, 2, 6, 3, 1, 5 ]
[ 4, 6, 2, 1, 3, 5 ]
[ 6, 4, 1, 2, 5, 3 ]
[ 6, 1, 4, 5, 2, 3 ]
[ 1, 6, 5, 4, 3, 2 ]

etc. etc.

Note this image focuses on the (2) bell’s direction change, but the above way of thinking produces the same result:

Plain-bob-minor_2

I see.
This is a specific way to do it for 6 bells. The idea is to generalize from 3 bells to 12 bells, and why not for any number beyond. I do not know much about campanology, I am just interested in combinatory. So, for now, I am quite a bit busy, but I am going to study that and think about a way to implement it if indeed it is relevant to do so.
Meanwhile, you are welcome to propose solutions, even in pseudo-code.
:nerd_face:

1 Like