Do is not ¨returning¨ array (campanology)

In the following code I am manipulating an array. Everything works to plan except the last line of code. My expectation is that do would ¨return¨ the array that it has just swapped around, and then I could continue to use that array further in my patch. Instead I get the error message:

ERROR: syntax error, unexpected NAME, expecting $end
in interpreted text
line 31 char 4:

data.postln;
^^^^

Any illumination greatly appreciated.

var data;
var parts;
var size;
var change1;
var change2;
var reflection;

parts = 5; 
data = Array.fill(parts, {arg i; i});
data.postln;
size = data.size;
size = size/2;
size = size.asInteger;
change1 = size;
change1 = change1.asInteger;
change1.postln;
change2 = if(parts.odd, {size.asInteger}, {size-1});
change2.postln;
(
do(parts, {arg count;
	       x = count % 2;
	       data.postln;
	       if(x.even, 
		     {do(change1, {arg count1; data.swap(count1*2, count1*2+1) })}, 
		     {do(change2, {arg count2; data.swap(count2*2+1, count2*2+2) })})
	      
}
)
)
data.postln;

missing semicolon line 29.
note the extra parenthesis (lines 19 and 29) is not needed.

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