From 2d7da671d51b5d5501b6e861b35fa356577e348c Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 27 Oct 2020 15:22:17 +0000 Subject: [PATCH 01/13] trying the nested iterator, not conclusive at all --- .../12-windowed-clustered-segmentation.scd | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 4b88813..22adc7d 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -56,6 +56,7 @@ Routine{ ~kmeans = FluidKMeans(s,2,100); ~windowDS = FluidDataSet(s,\windowDS); ~windowLS = FluidLabelSet(s,\windowLS); +~slices.dump{|x|~sliceDict = x;}; ) ( @@ -63,47 +64,45 @@ Routine{ ~indices = [0]; ~head = 0; - ~sliceDict = Dictionary.new(4); - ~tempDict = Dictionary.new(4); - - ~slices.dump{|x|~sliceDict = x;}; - s.sync; + ~tempDict = (); while ( {~head <= (~originalslicesarray.size - ~winSize)}, { var step = ~winSize - 1; var nbass = []; + ~assignments = []; //run a process on ~winSize items from ~head (with an overlap of 1) //copy the items to a subdataset ~winSize.do{|i| ~tempDict.put((i.asString), ~sliceDict["data"][(i+~head).asString]);//here one could curate which stats to take "whichslices:%\n".postf(i+~head); }; - ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict])); - s.sync; - "% - loaded\n".postf(~head); + ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { + "% - loaded\n".postf(~head); - //kmeans 2 and retrieve ordered array of class assignations - ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x;}); - s.sync; - "% - fitted1: ".postf(~head); nbass.postln; + //kmeans 2 and retrieve ordered array of class assignations + ~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x| + nbass = x; + "% - fitted1: ".postf(~head); nbass.postln; - // if (nbass.includes(0.0), { Routine{~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted2: ".postf(~head); nbass.postln; s.sync;});}.play; }); + // if (nbass.includes(0.0), { Routine{~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted2: ".postf(~head); nbass.postln; s.sync;});}.play; }); - ~windowLS.dump{|x|~assignments = x.at("data").asSortedArray.flop[1].flatten;}; - s.sync; - "% - assigned ".postf(~head); + ~windowLS.dump{|x| + ~assignments = x.at("data").asSortedArray.flop[1].flatten; + "% - assigned ".postf(~head); - ~assignments.postln; - - step.do{|i| - if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); - }; + ~assignments.postln; + step.do{|i| + if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); + }; + }; + }); + }); + s.sync; ~head = ~head + step; "-----------------".postln; }); - //leftovers if ( (~originalslicesarray.size - ~head) > 1, { //run a process on (a.size - ~head) items from ~head From 2b92864757a1fc0df275a156e440f801a7d96b3d Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 2 Nov 2020 15:28:55 +0000 Subject: [PATCH 02/13] this condition trick is genius --- .../12-windowed-clustered-segmentation.scd | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 22adc7d..b29e3d1 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -70,6 +70,7 @@ Routine{ { var step = ~winSize - 1; var nbass = []; + var cond = Condition.new; ~assignments = []; //run a process on ~winSize items from ~head (with an overlap of 1) //copy the items to a subdataset @@ -85,7 +86,16 @@ Routine{ nbass = x; "% - fitted1: ".postf(~head); nbass.postln; - // if (nbass.includes(0.0), { Routine{~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted2: ".postf(~head); nbass.postln; s.sync;});}.play; }); + if (nbass.includes(0.0), { + ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| + nbass = x; "% - fitted2: ".postf(~head); nbass.postln; + if (nbass.includes(0.0), { + ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| + nbass = x; "% - fitted3: ".postf(~head); nbass.postln; + }); + }); + }); + }); ~windowLS.dump{|x| ~assignments = x.at("data").asSortedArray.flop[1].flatten; @@ -95,11 +105,13 @@ Routine{ step.do{|i| if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); + }; + cond.unhang; }; }); }); - s.sync; + cond.hang; ~head = ~head + step; "-----------------".postln; }); From 09a2c48c50a458d342a2b9e50bcb05c7762332a9 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 2 Nov 2020 15:38:51 +0000 Subject: [PATCH 03/13] added the reaper export --- .../12-windowed-clustered-segmentation.scd | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index b29e3d1..166f75e 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -115,7 +115,7 @@ Routine{ ~head = ~head + step; "-----------------".postln; }); - //leftovers + //leftovers (half baked, needs to run it all properly but hey, let's fix it first if ( (~originalslicesarray.size - ~head) > 1, { //run a process on (a.size - ~head) items from ~head (~originalslicesarray.size - ~head - 1).do{|i| @@ -123,6 +123,9 @@ Routine{ // (~head+i).postln; }; }); + //add the endoffile indice to the array + ~indices = ~indices ++ (b.numFrames); + ~indices.postln; }.play; ) @@ -131,3 +134,32 @@ Routine{ {var i = 4;BufRd.ar(1,b,Line.ar(~indices[i],~indices[i+1],(~indices[i+1] - ~indices[i])/b.sampleRate, doneAction: 2))}.play; //export to reaper +( +//first create a new file that ends with rpp - it will overwrite if the file exists +f = File.new("/tmp/clusteredslices.rpp","w+"); + +if (f.isOpen , { + //write the header + f.write("\n>\n");}; + //write the track footer + f.write(">\n"); + + // a second track with the new ~indices + //write the track header + f.write("\n>\n");}; + //write the track footer + f.write(">\n"); + + //write the footer + f.write(">\n"); + f.close; +}); +) From e5223ef0e5167304c417e70b43743393dad8008e Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 2 Nov 2020 15:57:37 +0000 Subject: [PATCH 04/13] corrected the last bloc --- .../12-windowed-clustered-segmentation.scd | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 166f75e..69480d0 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -117,13 +117,52 @@ Routine{ }); //leftovers (half baked, needs to run it all properly but hey, let's fix it first if ( (~originalslicesarray.size - ~head) > 1, { + var nbass = []; + var cond = Condition.new; + ~assignments = []; //run a process on (a.size - ~head) items from ~head - (~originalslicesarray.size - ~head - 1).do{|i| - if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); - // (~head+i).postln; + //copy the items to a subdataset + (~originalslicesarray.size - ~head).do{|i| + ~tempDict.put((i.asString), ~sliceDict["data"][(i+~head).asString]);//here one could curate which stats to take + "whichslices:%\n".postf(i+~head); }; + ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { + "% - loaded\n".postf(~head); + + //kmeans 2 and retrieve ordered array of class assignations + ~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x| + nbass = x; + "% - fitted1: ".postf(~head); nbass.postln; + + if (nbass.includes(0.0), { + ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| + nbass = x; "% - fitted2: ".postf(~head); nbass.postln; + if (nbass.includes(0.0), { + ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| + nbass = x; "% - fitted3: ".postf(~head); nbass.postln; + }); + }); + }); + }); + + ~windowLS.dump{|x| + ~assignments = x.at("data").asSortedArray.flop[1].flatten; + "% - assigned ".postf(~head); + + ~assignments.postln; + + (~originalslicesarray.size - ~head - 1).do{|i| + if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); + + }; + cond.unhang; + }; + }); + }); + cond.hang; + "done".postln; }); - //add the endoffile indice to the array + //add the endoffile indice to the array ~indices = ~indices ++ (b.numFrames); ~indices.postln; From 25dce02ce8ced13296ef6b6dbd05c9b38cff1b99 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 3 Nov 2020 11:30:46 +0000 Subject: [PATCH 05/13] now a proper recursive function! --- .../12-windowed-clustered-segmentation.scd | 137 ++++++------------ 1 file changed, 45 insertions(+), 92 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 69480d0..49c017d 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -59,116 +59,68 @@ Routine{ ~slices.dump{|x|~sliceDict = x;}; ) +//the windowed function ( -Routine{ - ~indices = [0]; - ~head = 0; - - ~tempDict = (); - - while ( {~head <= (~originalslicesarray.size - ~winSize)}, - { - var step = ~winSize - 1; - var nbass = []; - var cond = Condition.new; - ~assignments = []; - //run a process on ~winSize items from ~head (with an overlap of 1) - //copy the items to a subdataset - ~winSize.do{|i| - ~tempDict.put((i.asString), ~sliceDict["data"][(i+~head).asString]);//here one could curate which stats to take - "whichslices:%\n".postf(i+~head); - }; - ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { - "% - loaded\n".postf(~head); +~windowedFunct = {arg head, winSize; + var nbass = [], assignments = [], tempDict; + //check the size of everything to not overrun + winSize = (~originalslicesarray.size - head).min(winSize); + //copy the items to a subdataset from hear + winSize.do{|i| + ~tempDict.put((i.asString), ~sliceDict["data"][(i+head).asString]);//here one could curate which stats to take + "whichslices:%\n".postf(i+head); + }; + ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { + "% - loaded\n".postf(head); - //kmeans 2 and retrieve ordered array of class assignations - ~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x| - nbass = x; - "% - fitted1: ".postf(~head); nbass.postln; + //kmeans 2 and retrieve ordered array of class assignations + ~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x| + nbass = x; + "% - fitted1: ".postf(head); nbass.postln; + if (nbass.includes(0.0), { + ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| + nbass = x; "% - fitted2: ".postf(head); nbass.postln; if (nbass.includes(0.0), { ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| - nbass = x; "% - fitted2: ".postf(~head); nbass.postln; - if (nbass.includes(0.0), { - ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| - nbass = x; "% - fitted3: ".postf(~head); nbass.postln; - }); - }); + nbass = x; "% - fitted3: ".postf(head); nbass.postln; }); }); - - ~windowLS.dump{|x| - ~assignments = x.at("data").asSortedArray.flop[1].flatten; - "% - assigned ".postf(~head); - - ~assignments.postln; - - step.do{|i| - if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); - - }; - cond.unhang; - }; }); }); - cond.hang; - ~head = ~head + step; - "-----------------".postln; - }); - //leftovers (half baked, needs to run it all properly but hey, let's fix it first - if ( (~originalslicesarray.size - ~head) > 1, { - var nbass = []; - var cond = Condition.new; - ~assignments = []; - //run a process on (a.size - ~head) items from ~head - //copy the items to a subdataset - (~originalslicesarray.size - ~head).do{|i| - ~tempDict.put((i.asString), ~sliceDict["data"][(i+~head).asString]);//here one could curate which stats to take - "whichslices:%\n".postf(i+~head); - }; - ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { - "% - loaded\n".postf(~head); - - //kmeans 2 and retrieve ordered array of class assignations - ~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x| - nbass = x; - "% - fitted1: ".postf(~head); nbass.postln; - - if (nbass.includes(0.0), { - ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| - nbass = x; "% - fitted2: ".postf(~head); nbass.postln; - if (nbass.includes(0.0), { - ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| - nbass = x; "% - fitted3: ".postf(~head); nbass.postln; - }); - }); - }); - }); - ~windowLS.dump{|x| - ~assignments = x.at("data").asSortedArray.flop[1].flatten; - "% - assigned ".postf(~head); + ~windowLS.dump{|x| + ~assignments = x.at("data").asSortedArray.flop[1].flatten; + "% - assigned ".postf(head); - ~assignments.postln; + ~assignments.postln; - (~originalslicesarray.size - ~head - 1).do{|i| - if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])}); + (winSize-1).do{|i| + if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1])}); - }; - cond.unhang; }; - }); + //if we still have some frames to do, do them + if (((head+winSize) < ~originalslicesarray.size), { + "-----------------".postln; + ~windowedFunct.value(head + winSize, winSize); + }, {~indices = ~indices ++ (b.numFrames); "done".postln;});//if we're done close the books + }; }); - cond.hang; - "done".postln; }); - //add the endoffile indice to the array - ~indices = ~indices ++ (b.numFrames); - - ~indices.postln; -}.play; +} ) +//the function + +~indices = [0]; +~tempDict = (); + +~windowedFunct.value(0, 4); + +~indices.postln; + +~windowDS.print + {var i = 8;BufRd.ar(1,b,Line.ar(~originalslicesarray[i],~originalslicesarray[i+1],(~originalslicesarray[i+1] - ~originalslicesarray[i])/b.sampleRate, doneAction: 2))}.play; {var i = 4;BufRd.ar(1,b,Line.ar(~indices[i],~indices[i+1],(~indices[i+1] - ~indices[i])/b.sampleRate, doneAction: 2))}.play; @@ -202,3 +154,4 @@ if (f.isOpen , { f.close; }); ) + From dc6ad1e410ca46a800afa47381fe0d43bf0805d2 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 3 Nov 2020 11:44:33 +0000 Subject: [PATCH 06/13] tigher variable scope --- .../12-windowed-clustered-segmentation.scd | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 49c017d..3cd8501 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -62,15 +62,15 @@ Routine{ //the windowed function ( ~windowedFunct = {arg head, winSize; - var nbass = [], assignments = [], tempDict; + var nbass = [], assignments = [], tempDict = (); //check the size of everything to not overrun winSize = (~originalslicesarray.size - head).min(winSize); //copy the items to a subdataset from hear winSize.do{|i| - ~tempDict.put((i.asString), ~sliceDict["data"][(i+head).asString]);//here one could curate which stats to take + tempDict.put((i.asString), ~sliceDict["data"][(i+head).asString]);//here one could curate which stats to take "whichslices:%\n".postf(i+head); }; - ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]), action: { + ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, tempDict]), action: { "% - loaded\n".postf(head); //kmeans 2 and retrieve ordered array of class assignations @@ -78,10 +78,10 @@ Routine{ nbass = x; "% - fitted1: ".postf(head); nbass.postln; - if (nbass.includes(0.0), { + if (nbass.includes(winSize.asFloat), { ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted2: ".postf(head); nbass.postln; - if (nbass.includes(0.0), { + if (nbass.includes(winSize.asFloat), { ~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted3: ".postf(head); nbass.postln; }); @@ -90,13 +90,13 @@ Routine{ }); ~windowLS.dump{|x| - ~assignments = x.at("data").asSortedArray.flop[1].flatten; + var assignments = x.at("data").asSortedArray.flop[1].flatten; "% - assigned ".postf(head); - ~assignments.postln; + assignments.postln; (winSize-1).do{|i| - if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1])}); + if (assignments[i+1] != assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1])}); }; //if we still have some frames to do, do them @@ -110,12 +110,11 @@ Routine{ } ) -//the function +//the job ~indices = [0]; -~tempDict = (); - -~windowedFunct.value(0, 4); +~windowedFunct.value(0, 5); +~kmeans.numClusters = 3; ~indices.postln; From bb2034d5ec0b2932e078d672bef9966c77c7a816 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 3 Nov 2020 12:45:53 +0000 Subject: [PATCH 07/13] explored less dimensions, more overlap --- .../12-windowed-clustered-segmentation.scd | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 3cd8501..054d02e 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -52,16 +52,30 @@ Routine{ //we overlap the analysis with the last (original) slice to check for continuity ( ~winSize = 4;//the number of consecutive items to split in 2 classes; +~curated = FluidDataSet(s,\curatedDS); ~query = FluidDataSetQuery(s); +~stan = FluidStandardize(s); ~kmeans = FluidKMeans(s,2,100); ~windowDS = FluidDataSet(s,\windowDS); ~windowLS = FluidLabelSet(s,\windowLS); -~slices.dump{|x|~sliceDict = x;}; ) +//normalise and curate stats +~query.clear +~query.addRange((5*19),19); +~query.transform(~slices,~curated); +~stan.fitTransform(~curated, ~curated); + +~curated.print +~curated.dump{|x|~sliceDict = x;}; + +//or +~curated.dump{|x|~sliceDict = x;}; + + //the windowed function ( -~windowedFunct = {arg head, winSize; +~windowedFunct = {arg head, winSize, overlap; var nbass = [], assignments = [], tempDict = (); //check the size of everything to not overrun winSize = (~originalslicesarray.size - head).min(winSize); @@ -70,7 +84,7 @@ Routine{ tempDict.put((i.asString), ~sliceDict["data"][(i+head).asString]);//here one could curate which stats to take "whichslices:%\n".postf(i+head); }; - ~windowDS.load(Dictionary.newFrom([\cols, 133, \data, tempDict]), action: { + ~windowDS.load(Dictionary.newFrom([\cols, 19, \data, tempDict]), action: { "% - loaded\n".postf(head); //kmeans 2 and retrieve ordered array of class assignations @@ -100,9 +114,9 @@ Routine{ }; //if we still have some frames to do, do them - if (((head+winSize) < ~originalslicesarray.size), { + if (((winSize + head) < ~originalslicesarray.size), { "-----------------".postln; - ~windowedFunct.value(head + winSize, winSize); + ~windowedFunct.value(head + winSize - overlap, winSize, overlap); }, {~indices = ~indices ++ (b.numFrames); "done".postln;});//if we're done close the books }; }); @@ -113,8 +127,12 @@ Routine{ //the job ~indices = [0]; -~windowedFunct.value(0, 5); +~windowedFunct.value(0, 4, 1); + +//try again with more clusters +~indices = [0]; ~kmeans.numClusters = 3; +~windowedFunct.value(0, 6,2); ~indices.postln; From d084350de76c7453e72d67294bf094ccc3692e97 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 3 Nov 2020 16:48:59 +0000 Subject: [PATCH 08/13] a few improvments: more iteration to kmeans, the indices are now in integer, and duplicates are removed, and there is a date stamp to the Reaper file --- .../12-windowed-clustered-segmentation.scd | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 054d02e..453218e 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -55,24 +55,20 @@ Routine{ ~curated = FluidDataSet(s,\curatedDS); ~query = FluidDataSetQuery(s); ~stan = FluidStandardize(s); -~kmeans = FluidKMeans(s,2,100); +~kmeans = FluidKMeans(s,2,1000); ~windowDS = FluidDataSet(s,\windowDS); ~windowLS = FluidLabelSet(s,\windowLS); ) //normalise and curate stats ~query.clear -~query.addRange((5*19),19); +~query.addRange((0*19),19); ~query.transform(~slices,~curated); ~stan.fitTransform(~curated, ~curated); ~curated.print ~curated.dump{|x|~sliceDict = x;}; -//or -~curated.dump{|x|~sliceDict = x;}; - - //the windowed function ( ~windowedFunct = {arg head, winSize, overlap; @@ -110,14 +106,14 @@ Routine{ assignments.postln; (winSize-1).do{|i| - if (assignments[i+1] != assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1])}); + if (assignments[i+1] != assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1]).asInteger}); }; //if we still have some frames to do, do them if (((winSize + head) < ~originalslicesarray.size), { "-----------------".postln; ~windowedFunct.value(head + winSize - overlap, winSize, overlap); - }, {~indices = ~indices ++ (b.numFrames); "done".postln;});//if we're done close the books + }, {~indices = ~indices.asSet.asArray.sort ++ (b.numFrames); "done".postln;});//if we're done close the books }; }); }); @@ -132,19 +128,19 @@ Routine{ //try again with more clusters ~indices = [0]; ~kmeans.numClusters = 3; -~windowedFunct.value(0, 6,2); +~windowedFunct.value(0,6,2); ~indices.postln; -~windowDS.print - +//check {var i = 8;BufRd.ar(1,b,Line.ar(~originalslicesarray[i],~originalslicesarray[i+1],(~originalslicesarray[i+1] - ~originalslicesarray[i])/b.sampleRate, doneAction: 2))}.play; {var i = 4;BufRd.ar(1,b,Line.ar(~indices[i],~indices[i+1],(~indices[i+1] - ~indices[i])/b.sampleRate, doneAction: 2))}.play; //export to reaper ( //first create a new file that ends with rpp - it will overwrite if the file exists -f = File.new("/tmp/clusteredslices.rpp","w+"); +f = File.new("/tmp/clusteredslices-" ++ Date.getDate.stamp + ++".rpp","w+"); if (f.isOpen , { //write the header @@ -170,5 +166,4 @@ if (f.isOpen , { f.write(">\n"); f.close; }); -) - +) \ No newline at end of file From 0e1a62b11a5f458926877c196ce507d4244206b2 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 5 Nov 2020 15:16:16 +0000 Subject: [PATCH 09/13] now adapted for using our folder/dataset creators --- .../Classes/FluidCorpusBuilders.sc | 1 + .../12-windowed-clustered-segmentation.scd | 123 +++++++++++------- 2 files changed, 77 insertions(+), 47 deletions(-) diff --git a/release-packaging/Classes/FluidCorpusBuilders.sc b/release-packaging/Classes/FluidCorpusBuilders.sc index b8cea79..efb81de 100644 --- a/release-packaging/Classes/FluidCorpusBuilders.sc +++ b/release-packaging/Classes/FluidCorpusBuilders.sc @@ -34,6 +34,7 @@ FluidLoadFolder { entry.add(\bounds->startEnd[i]); entry.add(\numchans->f.numChannels); entry.add(\sr->f.sampleRate); + entry.add(\path->f.path); index.add(label->entry); counter = counter + 1; if(counter == (files.size)) {action !? action.value(index)}; diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 453218e..e2031a7 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -1,50 +1,46 @@ -// load a source -b = Buffer.read(s,"/Volumes/machins/projets/newsfeed/sons/textes/Audio/synth/fromtexttospeech-AmE-George.wav") -b.play +// load a source folder +~loader = FluidLoadFolder("/Volumes/machins/projets/newsfeed/sons/textes/Audio/synth"); +~loader.play; //slightly oversegment with novelty //segments should still make sense but might cut a few elements in 2 or 3 -~originalslices = Buffer(s); -FluidBufNoveltySlice.process(s, b, indices: ~originalslices, feature: 1, kernelSize: 29, threshold: 0.05, filterSize: 5, hopSize: 128, action: {~originalslices.numFrames.postln;}) +~slicer = FluidSliceCorpus({ |src,start,num,dest| FluidBufNoveltySlice.kr(src,start,num,indices:dest, feature: 1, kernelSize: 29, threshold: 0.05, filterSize: 5, hopSize: 128)}); +~slicer.play(s, ~loader.buffer,~loader.index); //test the segmentation by looping them ( -{ - BufRd.ar(1, b, - Phasor.ar(0,1, - BufRd.kr(1, ~originalslices, - MouseX.kr(0, BufFrames.kr(~originalslices) - 1), 0, 1), - BufRd.kr(1, ~originalslices, - MouseX.kr(1, BufFrames.kr(~originalslices)), 0, 1), - BufRd.kr(1,~originalslices, - MouseX.kr(0, BufFrames.kr(~originalslices) - 1), 0, 1)), 0, 1); +~originalindices = Array.newFrom(~slicer.index.keys).sort{|a,b| ~slicer.index[a][\bounds][0]< ~slicer.index[b][\bounds][0]}.collect{|x|~slicer.index[x][\bounds]}; +d = {arg start=0, end = 44100; + BufRd.ar(1, ~loader.buffer, Phasor.ar(0,1,start,end,start),0,1); }.play; -) -//analyse each segment with MFCCs in a dataset -~originalslices.getn(0,~originalslices.numFrames, {|x|~originalslicesarray = x; if ((x.last != b.numFrames), {~originalslicesarray = ~originalslicesarray ++ (b.numFrames)}); });//retrieve the indices and add the file boundary at the end if not there already +w = Window.new.front; +b = ControlSpec(0, ~originalindices.size - 1, \linear, 1); // min, max, mapping, step +c = StaticText(w, Rect(340, 20, 50, 20)).align_(\center); +a = Slider(w, Rect(10, 20, 330, 20)) +.action_({var val = b.map(a.value).asInteger; + c.string_(val.asString); + d.set(\start,~originalindices[val][0], \end, ~originalindices[val][1]); +}); +) -//iterates through the -//a few buffers and our dataset - with back and forth from the language +//analyse each segment with 20 MFCCs in a dataset ( -~mfccs = Buffer(s); -~stats = Buffer(s); -~flat = Buffer(s); +~mfccbuf = 4.collect{Buffer.new}; +~statsbuf = 4.collect{Buffer.new}; +~flatbuf = 4.collect{Buffer.new}; ~slices = FluidDataSet(s,\slices); - -Routine{ - s.sync; - (~originalslicesarray.size - 1).do{|i| - FluidBufMFCC.process(s, b, startFrame: ~originalslicesarray[i], numFrames: (~originalslicesarray[i+1] - ~originalslicesarray[i]), numChans: 1,features: ~mfccs, numCoeffs: 20, action: { - FluidBufStats.process(s, ~mfccs, startChan: 1, stats: ~stats, action: { - FluidBufFlatten.process(s, ~stats, ~flat, action: { - ~slices.addPoint(i.asSymbol, ~flat); - }); - }); - }); - }; -}.play; +~extractor = FluidProcessSlices({|src,start,num,data| + var mfcc, stats, writer, flatten,mfccBuf, statsBuf, flatBuf, label, voice; + label = data.key; + voice = data.value[\voice]; + mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1, numCoeffs: 20, features:~mfccbuf[voice],trig:1,blocking: 1); + stats = FluidBufStats.kr(~mfccbuf[voice],stats:~statsbuf[voice],trig:Done.kr(mfcc),blocking: 1); + flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); + writer = FluidDataSetWr.kr(~slices,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1) +}); ) +~extractor.play(s,~loader.buffer, ~slicer.index); ~slices.print @@ -62,13 +58,16 @@ Routine{ //normalise and curate stats ~query.clear -~query.addRange((0*19),19); +~query.addRange((0*20)+1,19); ~query.transform(~slices,~curated); ~stan.fitTransform(~curated, ~curated); ~curated.print ~curated.dump{|x|~sliceDict = x;}; +~originalslicesarray = (~originalindices.flatten ++ ~loader.buffer.numFrames).asSet.asArray.sort +~orginalkeys = Array.newFrom(~slicer.index.keys).sort{|a,b| ~slicer.index[a][\bounds][0]< ~slicer.index[b][\bounds][0]} + //the windowed function ( ~windowedFunct = {arg head, winSize, overlap; @@ -77,7 +76,7 @@ Routine{ winSize = (~originalslicesarray.size - head).min(winSize); //copy the items to a subdataset from hear winSize.do{|i| - tempDict.put((i.asString), ~sliceDict["data"][(i+head).asString]);//here one could curate which stats to take + tempDict.put((i.asString), ~sliceDict["data"][(~orginalkeys[(i+head)]).asString]);//here one could curate which stats to take "whichslices:%\n".postf(i+head); }; ~windowDS.load(Dictionary.newFrom([\cols, 19, \data, tempDict]), action: { @@ -106,14 +105,17 @@ Routine{ assignments.postln; (winSize-1).do{|i| - if (assignments[i+1] != assignments[i], {~indices= ~indices ++ (~originalslicesarray[head+i+1]).asInteger}); + if (assignments[i+1] != assignments[i], { + ~newindices= ~newindices ++ (~originalslicesarray[head+i+1]).asInteger; + ~newkeys = ~newkeys ++ (~orginalkeys[head+i+1]); + }); }; //if we still have some frames to do, do them if (((winSize + head) < ~originalslicesarray.size), { "-----------------".postln; ~windowedFunct.value(head + winSize - overlap, winSize, overlap); - }, {~indices = ~indices.asSet.asArray.sort ++ (b.numFrames); "done".postln;});//if we're done close the books + }, {~newindices = (~newindices ++ ~loader.buffer.numFrames); "done".postln;});//if we're done close the books }; }); }); @@ -122,19 +124,24 @@ Routine{ //the job -~indices = [0]; +~newindices = [~originalslicesarray[0]]; ~newkeys = [~orginalkeys[0]]; ~windowedFunct.value(0, 4, 1); //try again with more clusters -~indices = [0]; +~newindices = [~originalslicesarray[0]]; ~newkeys = [~orginalkeys[0]]; ~kmeans.numClusters = 3; ~windowedFunct.value(0,6,2); -~indices.postln; +~newindices.postln; +~newkeys.postln; + +~newindices.size; +~newkeys.size; + +~newindices.last; +~newkeys.last; -//check -{var i = 8;BufRd.ar(1,b,Line.ar(~originalslicesarray[i],~originalslicesarray[i+1],(~originalslicesarray[i+1] - ~originalslicesarray[i])/b.sampleRate, doneAction: 2))}.play; -{var i = 4;BufRd.ar(1,b,Line.ar(~indices[i],~indices[i+1],(~indices[i+1] - ~indices[i])/b.sampleRate, doneAction: 2))}.play; +~slicer.index[~orginalkeys[0]] //export to reaper ( @@ -143,6 +150,7 @@ f = File.new("/tmp/clusteredslices-" ++ Date.getDate.stamp ++".rpp","w+"); if (f.isOpen , { + var path, prevpath ="", sr, count, dur; //write the header f.write("\n>\n");}; + ~orginalkeys.do{|v, i| + path = ~slicer.index[v][\path]; + if (path != prevpath, { + sr = ~slicer.index[v][\sr]; + prevpath = path; + count = 0; + }); + dur = ~originalslicesarray[i+1] - ~originalslicesarray[i]; + f.write("\n>\n"); + count = count + dur; + }; //write the track footer f.write(">\n"); // a second track with the new ~indices + prevpath = ""; //write the track header f.write("\n>\n");}; + ~newkeys.do{|v, i| + path = ~slicer.index[v][\path]; + if (path != prevpath, { + sr = ~slicer.index[v][\sr]; + prevpath = path; + count = 0; + }); + dur = ~newindices[i+1] - ~newindices[i]; + f.write("\n>\n"); + count = count + dur; + }; //write the track footer f.write(">\n"); From 4e321b92492cc8b9bb05d15ae98f53c6965af37d Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Fri, 6 Nov 2020 09:45:27 +0000 Subject: [PATCH 10/13] fix for overlap of 2. TODO: fix for all overlaps --- .../12-windowed-clustered-segmentation.scd | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index e2031a7..73e16e3 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -166,7 +166,9 @@ if (f.isOpen , { count = 0; }); dur = ~originalslicesarray[i+1] - ~originalslicesarray[i]; - f.write("\n>\n"); + if (dur > 0, { + f.write("\n>\n"); + }); count = count + dur; }; //write the track footer @@ -185,7 +187,9 @@ if (f.isOpen , { count = 0; }); dur = ~newindices[i+1] - ~newindices[i]; - f.write("\n>\n"); + if (dur > 0, { + f.write("\n>\n"); + }); count = count + dur; }; //write the track footer From 779b35cc1ed9b558c67dec4e498d67f79bb77da4 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Fri, 6 Nov 2020 11:41:19 +0000 Subject: [PATCH 11/13] various compositing of the clustering format- TODO: understand overlap consequences for realz TODO: maybe another step of conditional rejection (if 2 of 3 slice, then slice) --- .../12-windowed-clustered-segmentation.scd | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 73e16e3..49205ab 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -24,25 +24,31 @@ a = Slider(w, Rect(10, 20, 330, 20)) }); ) -//analyse each segment with 20 MFCCs in a dataset +//analyse each segment with 20 MFCCs in a dataset and spectralshapes in another one ( -~mfccbuf = 4.collect{Buffer.new}; +~featuresbuf = 4.collect{Buffer.new}; ~statsbuf = 4.collect{Buffer.new}; ~flatbuf = 4.collect{Buffer.new}; -~slices = FluidDataSet(s,\slices); +~slicesMFCC = FluidDataSet(s,\slicesM); +~slicesShapes = FluidDataSet(s,\slicesS); ~extractor = FluidProcessSlices({|src,start,num,data| - var mfcc, stats, writer, flatten,mfccBuf, statsBuf, flatBuf, label, voice; + var features, stats, writer, flatten,mfccBuf, statsBuf, flatBuf, label, voice; label = data.key; voice = data.value[\voice]; - mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1, numCoeffs: 20, features:~mfccbuf[voice],trig:1,blocking: 1); - stats = FluidBufStats.kr(~mfccbuf[voice],stats:~statsbuf[voice],trig:Done.kr(mfcc),blocking: 1); + features = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1, numCoeffs: 20, features:~featuresbuf[voice],trig:1,blocking: 1); + stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - writer = FluidDataSetWr.kr(~slices,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1) + writer = FluidDataSetWr.kr(~slicesMFCC,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + features = FluidBufSpectralShape.kr(src,startFrame:start,numFrames:num,numChans:1, features:~featuresbuf[voice],trig:Done.kr(writer),blocking: 1); + stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1); + flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); + writer = FluidDataSetWr.kr(~slicesShapes,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); }); ) ~extractor.play(s,~loader.buffer, ~slicer.index); -~slices.print +~slicesMFCC.print +~slicesShapes.print //run a window over consecutive segments, forcing them in 2 classes, and merging the consecutive segments of similar class //we overlap the analysis with the last (original) slice to check for continuity @@ -56,10 +62,26 @@ a = Slider(w, Rect(10, 20, 330, 20)) ~windowLS = FluidLabelSet(s,\windowLS); ) -//normalise and curate stats +//curate stats (MFCCs) +~query.clear +~query.addRange((0*20)+1,10); +~query.transform(~slicesMFCC,~curated); + +//OR +//curate stats (moments) ~query.clear -~query.addRange((0*20)+1,19); -~query.transform(~slices,~curated); +~query.addRange(0,3); +~query.transform(~slicesShapes,~curated); + +//OR +//curate both +~query.clear +~query.addColumn(0);//add col 0 (mean of mfcc0 as 'loudness') +~query.transform(~slicesMFCC,~curated);//mfcc0 as loudness +~query.clear; +~query.addRange(0,3);//add some spectral moments +~query.transformJoin(~slicesShapes, ~curated, ~curated);//join in centroids + ~stan.fitTransform(~curated, ~curated); ~curated.print @@ -79,7 +101,7 @@ a = Slider(w, Rect(10, 20, 330, 20)) tempDict.put((i.asString), ~sliceDict["data"][(~orginalkeys[(i+head)]).asString]);//here one could curate which stats to take "whichslices:%\n".postf(i+head); }; - ~windowDS.load(Dictionary.newFrom([\cols, 19, \data, tempDict]), action: { + ~windowDS.load(Dictionary.newFrom([\cols, ~sliceDict["cols"].asInteger, \data, tempDict]), action: { "% - loaded\n".postf(head); //kmeans 2 and retrieve ordered array of class assignations @@ -146,8 +168,7 @@ a = Slider(w, Rect(10, 20, 330, 20)) //export to reaper ( //first create a new file that ends with rpp - it will overwrite if the file exists -f = File.new("/tmp/clusteredslices-" ++ Date.getDate.stamp - ++".rpp","w+"); +f = File.new("/tmp/clusteredslices-" ++ Date.getDate.stamp ++".rpp","w+"); if (f.isOpen , { var path, prevpath ="", sr, count, dur; @@ -166,7 +187,7 @@ if (f.isOpen , { count = 0; }); dur = ~originalslicesarray[i+1] - ~originalslicesarray[i]; - if (dur > 0, { + if ( dur > 0, { f.write("\n>\n"); }); count = count + dur; From db297c384562aa51b976d3efe55e3c71f63cd265 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 18 Nov 2020 17:06:57 +0000 Subject: [PATCH 12/13] Dataest & Co: Clear server side caches on internal server reboot resolves #77 --- include/FluidSCWrapper.hpp | 30 ++++++++++++++++++- .../Classes/FluidManipulationClient.sc | 9 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index cc6c8eb..75b0458 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -698,6 +698,7 @@ struct LifetimePolicy } static void destroyClass(Unit* unit) { static_cast(unit)->~Wrapper(); } static void setup(InterfaceTable*, const char*){} + static void unload(){} }; /// Model objects @@ -763,7 +764,18 @@ struct LifetimePolicy auto pos = mRegistry.find(objectID); if(pos != mRegistry.end()) mRegistry.erase(objectID); }, &mRegistry); + + auto flushName = std::stringstream(); + flushName << "flush" << name; + + ft->fDefinePlugInCmd(flushName.str().c_str(), + [](World*, void*, sc_msg_iter*,void*) + { + unload(); + },nullptr); } + + static void unload(){ mRegistry.clear(); } private: static std::unordered_map mRegistry; @@ -825,8 +837,24 @@ struct LifetimePolicy mClientRegistry.erase(objectName); mParamsRegistry.erase(objectName); }, &mClientRegistry); - + + + auto flushName = std::stringstream(); + flushName << "flush" << name; + + ft->fDefinePlugInCmd(flushName.str().c_str(), + [](World*, void*, sc_msg_iter*,void*) + { + unload(); + },nullptr); } + + static void unload() + { + mClientRegistry.clear(); + mParamsRegistry.clear(); + } + private: static ClientPointer getClientPointer(Wrapper* wrapper) { diff --git a/release-packaging/Classes/FluidManipulationClient.sc b/release-packaging/Classes/FluidManipulationClient.sc index c39bebb..abf6015 100644 --- a/release-packaging/Classes/FluidManipulationClient.sc +++ b/release-packaging/Classes/FluidManipulationClient.sc @@ -53,9 +53,18 @@ FluidManipulationClient { if(server.serverRunning.not,{ (this.asString + "– server not running").error; ^nil }); + + NotificationCenter.register(server, \newAllocators, this, { + this.flush(server); + }); + ^super.newCopyArgs(server ?? {Server.default});//.baseinit(objectID,*args) } + *flush { |s| + s.sendMsg("/cmd","flush"++this.name); + } + makeDef { |defName,objectID,args| var initialVals = []; args!? { if(args.size > 0) {initialVals = args.unlace(2)[1].flatten}}; From 5cf7e32d0b42e3884482d13b27277a699f93548a Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Fri, 4 Dec 2020 09:05:40 +0000 Subject: [PATCH 13/13] added work-in-progress of 3d scaling example --- .../2-3Dscaling.scd | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 release-packaging/Examples/dataset/2-various other examples/scaling-dimension-as-weighting/2-3Dscaling.scd diff --git a/release-packaging/Examples/dataset/2-various other examples/scaling-dimension-as-weighting/2-3Dscaling.scd b/release-packaging/Examples/dataset/2-various other examples/scaling-dimension-as-weighting/2-3Dscaling.scd new file mode 100644 index 0000000..2d47818 --- /dev/null +++ b/release-packaging/Examples/dataset/2-various other examples/scaling-dimension-as-weighting/2-3Dscaling.scd @@ -0,0 +1,161 @@ +// Make: +// - A kmeans +// - a datasetquery +// - a normalizer +// - a standardizer +// - 3 DataSets of example points R-G-B descriptions +// - 3 DataSets for the scaled versions +// - 1 summative dataset and a LabelSet for predicted labels + +( +~classifier = FluidKMeans(s,5, 1000); +~query = FluidDataSetQuery(s); +~stan = FluidStandardize(s); +~norm = FluidNormalize(s); +~sourceR = FluidDataSet(s,\a3DsourceR); +~sourceG = FluidDataSet(s,\a3DsourceG); +~sourceB = FluidDataSet(s,\a3DsourceB); +~scaledR = FluidDataSet(s,\a3DscaledR); +~scaledG = FluidDataSet(s,\a3DscaledG); +~scaledB = FluidDataSet(s,\a3DscaledB); +~composited = FluidDataSet(s,\a3Dcomposited); +~labels = FluidLabelSet(s,\a3Dlabels); +) + +//Make some random, but clustered test points, each descriptor category in a separate dataset +( +~sourceR.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, 1.0.sum3rand]}.flatten))])); +~sourceG.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, 1.0.rand2]}.flatten))])); +~sourceB.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, (0.5.sum3rand).squared + [0.75,-0.1].choose]}.flatten))])); +) + +//here we manipulate + +//assemble the scaled dataset +( +~query.addColumn(0, { + ~query.transformJoin(~sourceB, ~sourceG, ~composited, { + ~query.transformJoin(~sourceR, ~composited, ~composited); + }); +}); +) + +~composited.print + +//Fit the classifier to the example DataSet and labels, and then run prediction on the test data into our mapping label set +~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict = x;};~composited.dump{|x|~compodict=x;};}); + +//Visualise: +( +w = Window("sourceClasses", Rect(128, 64, 820, 120)); +w.drawFunc = { + Pen.use{ + ~compodict["data"].keysValuesDo{|key, colour| + Pen.fillColor = Color.fromArray((colour * 0.5 + 0.5 ).clip(0,1) ++ 1); + Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict["data"].at(key).asInteger[0] * 20 + 10),15,15)); + }; + }; +}; +w.refresh; +w.front; +) + +// standardize our colours and rerun +( +~stan.fitTransform(~sourceR, ~scaledR, { + ~stan.fitTransform(~sourceG, ~scaledG, { + ~stan.fitTransform(~sourceB, ~scaledB, { + //assemble + ~query.addColumn(0, { + ~query.transformJoin(~scaledB, ~scaledG, ~composited, { + ~query.transformJoin(~scaledR, ~composited, ~composited, { + //fit + ~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};}); + }); + }); + }); + }); + }); +}); +) + +//Visualise: +( +w = Window("stanClasses", Rect(128, 64, 820, 120)); +w.drawFunc = { + Pen.use{ + ~compodict2["data"].keysValuesDo{|key, colour| + Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1); + Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15)); + }; + }; +}; +w.refresh; +w.front; +) + +//now let's normalise instead +( +~norm.fitTransform(~sourceR, ~scaledR, { + ~norm.fitTransform(~sourceG, ~scaledG, { + ~norm.fitTransform(~sourceB, ~scaledB, { + //assemble + ~query.addColumn(0, { + ~query.transformJoin(~scaledB, ~scaledG, ~composited, { + ~query.transformJoin(~scaledR, ~composited, ~composited, { + //fit + ~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};}); + }); + }); + }); + }); + }); +}); +) + +//Visualise: +( +w = Window("normClasses", Rect(128, 64, 820, 120)); +w.drawFunc = { + Pen.use{ + ~compodict2["data"].keysValuesDo{|key, colour| + Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1); + Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15)); + }; + }; +}; +w.refresh; +w.front; +) + +// let's mess up with the scaling of one dimension: let's multiply the range of Red by 10 +~norm.min = -10; +~norm.max = 10; +( +~norm.fitTransform(~sourceR, ~scaledR, { + //assemble + ~query.addColumn(0, { + ~query.transformJoin(~scaledB, ~scaledG, ~composited, { + ~query.transformJoin(~scaledR, ~composited, ~composited, { + //fit + ~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};}); + }); + }); + }); +}); +) + +//Visualise: +( +w = Window("norm10rClasses", Rect(128, 64, 820, 120)); +w.drawFunc = { + Pen.use{ + ~compodict2["data"].keysValuesDo{|key, colour| + Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1); + Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15)); + }; + }; +}; +w.refresh; +w.front; +)