Enable persistence for Dataset, Labelset and 'model' objects

viz. KDTree, KMeans,KNN, Normalize, PCA and Standardize. Most changes in 
FluidManipulationClient
nix
Owen Green 6 years ago
parent 1eabc42b24
commit 4b88b405d7

@ -1,64 +1,88 @@
FluidDataSetExistsError : Exception{
}
FluidDataSet : FluidManipulationClient {
var <>synth, <>server, <>id;
var <id;
classvar serverCaches;
*kr{ |name|
^this.new1('control',name);
*initClass {
serverCaches = FluidServerCache.new;
}
*at{ |server, id|
^serverCaches.tryPerform(\at, server,id)
}
*new { |server,name|
^super.new(server,name);
if(this.at(server,name).notNil){
FluidDataSetExistsError("A FluidDataset called % already exists.".format(name)).throw;
}
{^super.new(server,*FluidManipulationClient.prServerString(name)).init(name)}
}
init { |name, dims|
var ascii = name.ascii;
this.id = name;
// specialIndex = -1;
inputs = [ascii.size].addAll(ascii)++dims++Done.none++FluidManipulationClient.nonBlocking;
init {|name|
id = name;
this.cache;
}
cache {
serverCaches.initCache(server);
serverCaches.put(server,id,this);
}
asString {
^"FluidDataSet(%)".format(id).asString;
}
asUGenInput {
^id.asString;
}
addPoint{|label, buffer, action|
this.pr_sendMsg(\addPoint,[label.asString,buffer.asUGenInput],action);
this.prSendMsg(\addPoint,[label.asString,buffer.asUGenInput],action);
}
getPoint{|label, buffer, action|
this.pr_sendMsg(\getPoint,[label.asString,buffer.asUGenInput],action);
this.prSendMsg(\getPoint,[label.asString,buffer.asUGenInput],action);
}
updatePoint{|label, buffer, action|
this.pr_sendMsg(\updatePoint,[label.asString,buffer.asUGenInput],action);
this.prSendMsg(\updatePoint,[label.asString,buffer.asUGenInput],action);
}
deletePoint{|label, action|
this.pr_sendMsg(\deletePoint,[label.asString],action);
this.prSendMsg(\deletePoint,[label.asString],action);
}
cols {|action|
this.pr_sendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
read{|filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{|filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
size { |action|
this.pr_sendMsg(\size,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\size,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
clear { |action|
this.pr_sendMsg(\clear,[],action);
this.prSendMsg(\clear,[],action);
}
free { |action|
this.pr_sendMsg(\free,[],action);
serverCaches.remove(server,id);
if(server.serverRunning){this.prSendMsg(\free,[],action)};
super.free;
}
*freeAll { |server|
serverCaches.tryPerform(\clearCache,server);
}
}

@ -1,27 +1,42 @@
FluidKDTree : FluidManipulationClient {
var id;
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
init {|uid|
id = uid;
}
fit{|dataset,action|
this.pr_sendMsg(\fit,[dataset.asString],action);
this.prSendMsg(\fit,[dataset.asUGenInput],action);
}
kNearest{ |buffer, k,action|
this.pr_sendMsg(\kNearest,[buffer.asUGenInput,k],action,k.collect{string(FluidMessageResponse,_,_)});
this.prSendMsg(\kNearest,[buffer.asUGenInput,k],action,k.collect{string(FluidMessageResponse,_,_)});
}
kNearestDist { |buffer, k,action|
this.pr_sendMsg(\kNearestDist,[buffer.asUGenInput,k],action,[numbers(FluidMessageResponse,_,k,_)]);
this.prSendMsg(\kNearestDist,[buffer.asUGenInput,k],action,[numbers(FluidMessageResponse,_,k,_)]);
}
cols { |action|
this.pr_sendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
read{ |filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{ |filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
free { |action|
if(server.serverRunning){this.prSendMsg(\free,[],action)};
super.free;
}
}

@ -2,33 +2,42 @@ FluidKMeans : FluidManipulationClient {
var <>k;
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
init {|uid|
id = uid;
}
fit{|dataset,k, maxIter = 100, buffer, action|
buffer = buffer ? -1;
this.k = k;
this.pr_sendMsg(\fit,[dataset.asString, k,maxIter, buffer.asUGenInput],action,[numbers(FluidMessageResponse,_,k,_)]);
this.prSendMsg(\fit,[dataset.asString, k,maxIter, buffer.asUGenInput],action,[numbers(FluidMessageResponse,_,k,_)]);
}
predict{ |dataset, labelset,action|
this.pr_sendMsg(\predict,[dataset.asString, labelset.asString],action,[numbers(FluidMessageResponse,_,this.k,_)]);
this.prSendMsg(\predict,[dataset.asString, labelset.asString],action,[numbers(FluidMessageResponse,_,this.k,_)]);
}
getClusters{ |dataset, labelset,action|
this.pr_sendMsg(\getClusters,[dataset.asString, labelset.asString],action);
this.prSendMsg(\getClusters,[dataset.asString, labelset.asString],action);
}
predictPoint { |buffer, action|
this.pr_sendMsg(\predictPoint,[buffer.asUGenInput],action,[number(FluidMessageResponse,_,_)]);
this.prSendMsg(\predictPoint,[buffer.asUGenInput],action,[number(FluidMessageResponse,_,_)]);
}
cols { |action|
this.pr_sendMsg(\cols,[],action,[number(FluidMessageResponse,_,_)]);
this.prSendMsg(\cols,[],action,[number(FluidMessageResponse,_,_)]);
}
read{ |filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{ |filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
}

@ -1,15 +1,23 @@
FluidKNN : FluidManipulationClient {
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
init {|uid|
id = uid;
}
fit{|dataset, action|
this.pr_sendMsg(\fit,[dataset.asString],action);
this.prSendMsg(\fit,[dataset.asString],action);
}
classifyPoint{ |buffer, labelset, k, action|
this.pr_sendMsg(\classify,[buffer.asUGenInput, labelset.asString, k],action,[string(FluidMessageResponse,_,_)]);
this.prSendMsg(\classify,[buffer.asUGenInput, labelset.asString, k],action,[string(FluidMessageResponse,_,_)]);
}
regressPoint { |buffer,dataset, k, action|
this.pr_sendMsg(\regress,[buffer.asUGenInput, dataset.asString,k],action,[number(FluidMessageResponse,_,_)]);
this.prSendMsg(\regress,[buffer.asUGenInput, dataset.asString,k],action,[number(FluidMessageResponse,_,_)]);
}
}

@ -1,55 +1,83 @@
FluidLabelSetExistsError : Exception{
}
FluidLabelSet : FluidManipulationClient {
var <> synth, <> server, <>id;
var <id;
classvar serverCaches;
*kr{ |name|
^this.multiNew('control',name);
*initClass {
serverCaches = FluidServerCache.new;
}
*at{ |server, id|
^serverCaches.tryPerform(\at, server,id)
}
*new { |server,name|
^super.new(server,name);
serverCaches.at(server,name) !? {
FluidLabelSetExistsError("A FluidLabelSet called % already exists.".format(name)).throw;
};
^super.new(server,*FluidManipulationClient.prServerString(name)).init(name)
}
init { |name|
var ascii = name.ascii;
this.id = name;
inputs = [ascii.size].addAll(ascii)++Done.none++FluidManipulationClient.nonBlocking;
this.cache;
}
cache {
serverCaches.initCache(server);
serverCaches.put(server,id,this);
}
asString {
^"FluidLabelSet(%)".format(id).asString;
}
asUGenInput{
^id.asString;
}
addLabel{|id, label, action|
this.pr_sendMsg(\addLabel,[id.asString, label.asString],action);
this.prSendMsg(\addLabel,[id.asString, label.asString],action);
}
getLabel{|id, action|
this.pr_sendMsg(\getLabel,[id.asString],action,[string(FluidMessageResponse,_,_)]);
this.prSendMsg(\getLabel,[id.asString],action,[string(FluidMessageResponse,_,_)]);
}
deleteLabel{|id, action|
this.pr_sendMsg(\deleteLabel,[id.asString],action);
this.prSendMsg(\deleteLabel,[id.asString],action);
}
cols {|action|
this.pr_sendMsg(\cols,[],action,[number(FluidMessageResponse,_,_)]);
this.prSendMsg(\cols,[],action,[number(FluidMessageResponse,_,_)]);
}
read{|filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{|filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
size { |action|
this.pr_sendMsg(\size,[],action,[number(FluidMessageResponse,_,_)]);
this.prSendMsg(\size,[],action,[number(FluidMessageResponse,_,_)]);
}
clear { |action|
this.pr_sendMsg(\clear,[],action);
this.prSendMsg(\clear,[],action);
}
free { |action|
serverCaches.remove(server,id);
if(server.serverRunning){this.prSendMsg(\free,[],action)};
super.free;
}
*freeAll { |server|
serverCaches.tryPerform(\clearCache,server);
}
}

@ -1,41 +1,176 @@
FluidManipulationClient : UGen {
FluidProxyUgen : UGen {
const < nonBlocking = 0;
var <> synth, <> server;
var <>pluginname;
*kr {
^this.multiNew('control', Done.none, nonBlocking);
*kr { |pluginname...args|
^this.new1('control', pluginname,*args)
}
init { |pluginname...args|
this.pluginname = pluginname;
inputs = args++Done.none++0;
}
name{
^pluginname.asString;
}
}
FluidManipulationClient {
var <server;
var <synth,gen;
var bootFunc;
var synthDefLoaded,id, defName, <>ugen, updateFunc;
var nodeResponder;
var initTreeCondition;
var synthBeenSet = false;
var serverListener;
*prServerString{ |s|
var ascii = s.ascii;
^[ascii.size].addAll(ascii)
}
sendSynthDef { |...args|
var plugin = this.class.name.asSymbol;
if(server.hasBooted)
{
fork{
SynthDef(defName.asSymbol,{
var ugen = FluidProxyUgen.kr(plugin, *args);
this.ugen = ugen;
ugen
}).send(server);
server.sync;
synthDefLoaded = true;
updateFunc = {
//Sometimes Server.initTree seems to get called a bunch of
//times during boot: we can't be having extra instances
//However, once boot has finished, ending up here means cmd-. or server.freeAll
//has happened, and we just need to run
var shouldRun = (synthBeenSet.not.and(server.serverBooting))
.or(server.serverRunning.and(server.serverBooting.not));
if(shouldRun) {
synthBeenSet = true;
synth = nil;
this.updateSynth;
}
};
updateFunc.value;
ServerTree.add(updateFunc, server);
};
};
}
updateSynth {
if(server.hasBooted){
if(synthDefLoaded){
if(synth.isNil){
synth = Synth.after(server.defaultGroup,defName.asSymbol);
synth.register;
}
}
}{
synth !? {synth.free};
}
}
*new{ |server...args|
var synth, instance;
server = server ? Server.default;
if(server.serverRunning.not,{("ERROR:" + this.asString + " server not running").postln; ^nil});
synth = {instance = this.kr(*args)}.play(server);
instance.server = server;
instance.synth = synth;
^instance
if(server.serverRunning.not,{
(this.asString + " server not running").warn;
});
^super.newCopyArgs(server ?? {Server.default}).baseinit(*args)
}
pr_sendMsg { |msg, args, action,parser|
var c = Condition.new(false);
baseinit { |...args|
id = UniqueID.next;
synthDefLoaded = false;
defName = (this.class.name.asString ++ id);
if(server.serverRunning){ this.sendSynthDef(*args);};
bootFunc = {
ServerBoot.remove(bootFunc,server);
synth = nil;
this.sendSynthDef(*args);
};
ServerBoot.add(bootFunc,server);
ServerQuit.add({this.free;},server);
}
free{
ServerTree.remove(updateFunc,server);
ServerBoot.remove(bootFunc, server);
updateFunc = nil;
// synth !? {synth.tryPerform(\free)};//
synth = nil;
}
prSendMsg { |msg, args, action,parser|
if(this.server.serverRunning.not,{(this.asString + " server not running").error; ^nil});
synth !? {
OSCFunc(
{ |msg|
forkIfNeeded{
var result;
// msg.postln;
result = FluidMessageResponse.collectArgs(parser,msg.drop(3));
this.server.sync;
c.test = true;
c.signal;
if(action.notNil){action.value(result)}{action.value};
}
},'/'++msg).oneShot;
},'/'++msg, server.addr, nil,[synth.nodeID]).oneShot;
server.listSendMsg(['/u_cmd',synth.nodeID,ugen.synthIndex,msg].addAll(args));
}
}
}
FluidServerCache {
var cache;
*new{ ^super.new.init }
init{
cache = IdentityDictionary.new;
}
at { |server,id|
^cache[server].tryPerform(\at,id)
}
includesKey{|server,key|
^cache[server].tryPerform(\includesKey,key)
}
this.server.listSendMsg(['/u_cmd',this.synth.nodeID,this.synthIndex,msg].addAll(args));
put {|server,id,x|
cache[server][id] = x;
}
remove { |server,id|
cache[server]!? {cache[server].removeAt(id)};
}
forkIfNeeded { c.wait };
initCache {|server|
cache[server] ?? {
cache[server] = IdentityDictionary.new;
ServerQuit.add({this.clearCache(server)},server);
NotificationCenter.register(server,\newAllocators,this, {
this.clearCache(server);
});
}
}
clearCache { |server|
cache[server] !? { cache.removeAt(server) !? {|x| x.tryPerform(\free) } };
}
}

@ -1,35 +1,36 @@
FluidNormalize : FluidManipulationClient {
*kr{ |min = 0, max = 1|
^this.multiNew('control',min, max, Done.none, super.nonBlocking);
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
*new { |server,min = 0 ,max = 1|
^super.new(server,min,max);
init {|uid|
id = uid;
}
fit{|dataset, action|
this.pr_sendMsg(\fit,[dataset.asString],action);
this.prSendMsg(\fit,[dataset.asString],action);
}
normalize{|sourceDataset, destDataset, action|
this.pr_sendMsg(\normalize,[sourceDataset.asString, destDataset.asString],action);
this.prSendMsg(\normalize,[sourceDataset.asString, destDataset.asString],action);
}
normalizePoint{|sourceBuffer, destBuffer, action|
this.pr_sendMsg(\normalizePoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
this.prSendMsg(\normalizePoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
}
cols {|action|
this.pr_sendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
read{|filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{|filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
}

@ -1,36 +1,46 @@
FluidPCA : FluidManipulationClient {
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
init {|uid|
id = uid;
}
fit{|dataset, k, action|
this.pr_sendMsg(\fit,[dataset.asString, k],action);
this.prSendMsg(\fit,[dataset.asString, k],action);
}
transform{|sourceDataset, destDataset, action|
this.pr_sendMsg(\transform,[sourceDataset.asString, destDataset.asString],action);
this.prSendMsg(\transform,[sourceDataset.asString, destDataset.asString],action);
}
fitTransform{|sourceDataset, k, destDataset, action|
this.pr_sendMsg(\fitTransform,[sourceDataset.asString,k, destDataset.asString],action);
this.prSendMsg(\fitTransform,[sourceDataset.asString,k, destDataset.asString],action);
}
transformPoint{|sourceBuffer, destBuffer, action|
this.pr_sendMsg(\transformPoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
this.prSendMsg(\transformPoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
}
cols {|action|
this.pr_sendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
rows {|action|
this.pr_sendMsg(\rows,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\rows,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
read{|filename,action|
this.pr_sendMsg(\read,[filename],action);
this.prSendMsg(\read,[filename],action);
}
write{|filename,action|
this.pr_sendMsg(\write,[filename],action);
this.prSendMsg(\write,[filename],action);
}
}

@ -26,18 +26,18 @@ FluidProviderTest : UGen {
}
addPoint{|server, nodeID, args, action|
this.pr_sendMsg(server, nodeID, 'addPoint',args,action);
this.prSendMsg(server, nodeID, 'addPoint',args,action);
}
updatePoint{|server, nodeID, args, action|
this.pr_sendMsg(server, nodeID, 'updatePoint',args,action);
this.prSendMsg(server, nodeID, 'updatePoint',args,action);
}
deletePoint{|server, nodeID, args, action|
this.pr_sendMsg(server,nodeID, 'deletePoint',args,action);
this.prSendMsg(server,nodeID, 'deletePoint',args,action);
}
pr_sendMsg { |server, nodeID, msg, args, action,parser|
prSendMsg { |server, nodeID, msg, args, action,parser|
server = server ? Server.default;

@ -1,27 +1,36 @@
FluidStandardize : FluidManipulationClient {
*new {|server|
var uid = UniqueID.next;
^super.new(server,uid).init(uid);
}
init {|uid|
id = uid;
}
fit{|dataset, action|
this.pr_sendMsg(\fit,[dataset.asString],action);
this.prSendMsg(\fit,[dataset.asString],action);
}
standardize{|sourceDataset, destDataset, action|
this.pr_sendMsg(\standardize,[sourceDataset.asString, destDataset.asString],action);
this.prSendMsg(\standardize,[sourceDataset.asString, destDataset.asString],action);
}
standardizePoint{|sourceBuffer, destBuffer, action|
this.pr_sendMsg(\standardizePoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
this.prSendMsg(\standardizePoint,[sourceBuffer.asUGenInput, destBuffer.asUGenInput],action);
}
cols {|action|
this.pr_sendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
}
read{|filename,action|
this.pr_sendMsg(\read,[filename.asString],action);
this.prSendMsg(\read,[filename.asString],action);
}
write{|filename,action|
this.pr_sendMsg(\write,[filename.asString],action);
this.prSendMsg(\write,[filename.asString],action);
}
}

@ -21,11 +21,11 @@ FluidSubscriberTest : UGen {
}
providerLookup { |server, nodeID, label, action|
this.pr_sendMsg(server, nodeID, 'providerLookup', label, action,
this.prSendMsg(server, nodeID, 'providerLookup', label, action,
[string(FluidMessageResponse,_,_),numbers(FluidMessageResponse,_,2,_)] );
}
pr_sendMsg { |server, nodeID, msg, args, action,parser|
prSendMsg { |server, nodeID, msg, args, action,parser|
server = server ? Server.default;

@ -0,0 +1,105 @@
TestFluidCorpusManipulationServer : UnitTest
{
var waitForCounts, countsListener;
setUp{
waitForCounts = Condition.new(false);
countsListener = { |s,changed|
if(changed == \counts) {
waitForCounts.test = true;
waitForCounts.signal;
}
};
Server.default.addDependant(countsListener);
}
tearDown{
Server.default.removeDependant(countsListener);
Server.default.quit;
}
test_DataSetPersistence{
var foo, bar, tree, testPoint;
foo = FluidDataSet(Server.default,\foo);
this.bootServer(Server.default);
while {Server.default.serverRunning.not}{0.2.wait};
waitForCounts.test = false;
waitForCounts.wait;
this.assertEquals(Server.default.numSynths,1,"Dataset: One Synth present after deferred boot");
waitForCounts.test = false;
foo.free;
Server.default.freeAll;
waitForCounts.wait;
this.assertEquals(Server.default.numSynths,0,"Dataset: One Synth present via cretation after boot");
//Uniqueness test (difficult to run with previous instance of foo, because
//UnitTest.bootServer messes with Server alloctors and screws up the ID cache
foo = FluidDataSet(Server.default,\foo);
this.assertException({
bar = FluidDataSet(Server.default,\foo);
},FluidDataSetExistsError,"DataSetDuplicateError on reused name", onFailure:{
"Exception fail".postln;
});
waitForCounts.test = false;
bar = FluidDataSet(Server.default,\bar);
waitForCounts.wait;
this.assertEquals(Server.default.numSynths,2,"Dataset: Two Synths present after new Dataset added");
testPoint = Buffer.alloc(Server.default,8);
Server.default.sync;
testPoint.setn(0,[1,2,3,4,5,6,7,8]);
Server.default.sync;
foo.addPoint(\one,testPoint);
Server.default.sync;
foo.size({|size|
this.assertEquals(size,1,"Dataset size is 1");
});
Server.default.sync;
foo.cols({|cols|
this.assertEquals(cols,8,"Dataset cols is 8");
});
Server.default.sync;
waitForCounts.test = false;
tree = FluidKDTree(Server.default);
waitForCounts.wait;
this.assert(tree.synth.notNil,"Tree should have a valid synth");
this.assertEquals(Server.default.numSynths,3,"Dataset: Three Synths remain after cmd-.");
tree.fit(foo);
Server.default.sync;
tree.cols({|cols|
this.assertEquals(cols,8,"KDTree correct dims after fit")
});
Server.default.sync;
//Test cmd-period resistance
waitForCounts.test = false;
Server.default.freeAll;
Server.default.sync;
Server.default.sync;
waitForCounts.wait;
this.assertEquals(Server.default.numSynths,3,"Dataset: Three Synths remain after cmd-.");
foo.size({|size|
this.assertEquals(size,1,"Dataset size is still 1 after Cmd-.");
});
Server.default.sync;
foo.cols({|cols|
this.assertEquals(cols,8,"Dataset cols is still 8 after Cmd-.");
});
Server.default.sync;
tree.cols({|cols| this.assertEquals(cols,8,"KDTree correct dims after Cmd-.")});
Server.default.sync;
}
}
Loading…
Cancel
Save