// sc.solar 18.10.01 // added do (recDo) // right indexing in recDo // proper posting in postln and post // added doSimple // added collect // added flop // added getDiagonal // added shape = dimensions // postln again for order < 2 // added sub // doSimple count arg i // optimized put and at for indices.size < 2 // added getPlane // added getRow // added getCol // flop in other direction for proper rows and cols // 2D convenience in getRow // added wrapAt, wrapPut and clipPut // added *fill // added getLine, putLine // getRow, getCol dependent on getLine // putRow, putCol dependent on putLine // added putSome, getSome // putLine,getLine dependent on putSome,getSome // getSome also for single elements // getDiagonal returns ArrayXD // added asArray, flat, flatten, reshape (prReshape) // added collectSimple // added +, -, ==, ==*, * for scalars // proper plopping // added indexAt // added indicesAt // added doSome // added doSomeSimple // added doRow, doCol, doLine // added doRowSimple, doColSimpls, doLineSimple // added collectRow, collectCol, collectLine // added collectRowSimple, collectColSimple, collectLineSimple // order as classvariable; this.order -> order // init with order, order 0 for empty arrays // added sum // added xsum // renamed: dimensions --> sizes; order --> dimension // added multi for evaluation (2D) // added isInRange // added mulElements // renamed sum-->sumAll // kicked xsum; use mulElements and sumAll instead // size=1 convenience in *newClear, wrapAt, wrapPut, clipPut // felix corrections // removed multi // renamed class to ArrayND // logical grouping // added row, col for more 2D convenience // added collect the hole story // found error in asArray and cleared // flop now returns this.flopped; not a new array // added a simple rotateSome approach // added simpleSize // dimensions in *Some start from 0; just like indices ArrayND[slot] : Array { var 1,{ n.do({ arg i; var dmul = 1; (i).do({ arg j; dmul = dmul * (sizes.at(j) ) }); pos = pos + (indices.at(i) * dmul) }); ^super.at(pos) },{ if(n == 1,{ ^super.at(indices.at(0)) },{ ^super.at(indices) }); }); } put { arg indices, val; var pos = 0, n; n = indices.size; if(n > 1,{ n.do({ arg i; var dmul = 1; (i).do({ arg j; dmul = dmul * (sizes.at(j) ) }); pos = pos + (indices.at(i) * dmul) }); ^super.put(pos,val) },{ if(n == 1,{ ^super.put(indices.at(0),val) },{ ^super.put(indices,val) }); }); } *fill { arg sizes, func; var arrayXD; arrayXD = this.new(sizes); arrayXD.do({ arg item, indices; arrayXD.put( indices, func.value(indices) ); }); ^arrayXD } *with { arg array, sizes; var arrayXD; sizes = sizes ? [array.size]; arrayXD = ArrayND.new(sizes); arrayXD.doSimple({ arg item, i; arrayXD.put( i, array.at(i) ); }); ^arrayXD } // basic instance methods shape { ^sizes; } simpleSize { var size = 1; sizes.do({ arg sizeN; size = size*sizeN; }); ^(size); } order { ^dimension; } indexAt { arg indices; var pos = 0, n; n = indices.size; if(n > 1,{ n.do({ arg i; var dmul = 1; (i).do({ arg j; dmul = dmul * (sizes.at(j) ) }); pos = pos + (indices.at(i) * dmul) }); if( pos > this.size ,{"Warning: index out of range".postln}); ^pos },{ if(n == 1,{ if(indices.at(0) > this.size ,{"Warning: index out of range".postln}); ^indices.at(0) },{ if(indices > this.size ,{"Warning: index out of range".postln}); ^indices }); }); } indicesAt { arg index; var indices, diver, putter; if( index > this.size,{"Warning: index out of range".postln}); indices = sizes.copy; dimension.do({ arg n; var count; count = dimension - n -1; diver = 1; count.do({ arg m; diver = diver*sizes.at(m) }); putter = index.div(diver); indices.put( count, putter) ; index = index -(diver*putter); }); ^indices; } isInRange { arg indices; var indSize = 1; if( indices.size > 0,{ indices.do({ arg item,i; indSize = indSize * (item+1) }); ^(indSize-1 < this.size); },{ ^(indices < (this.size)); }); } wrapAt { arg indices; if(indices.size == 0,{ indices = indices.wrap(0,this.size-1) },{ indices.do({ arg item,i; indices.put(i, item.wrap(0, sizes.at(i)-1) ); }); }); ^this.at(indices); } wrapPut { arg indices, val; if(indices.size == 0,{ indices = indices.wrap(0,this.size-1) },{ indices.do({ arg item,i; indices.put(i, item.wrap(0, sizes.at(i)-1) ); }); }); ^this.put(indices, val); } clipPut { arg indices, val; if(indices.size == 0,{ indices = indices.clip(0,this.size-1) },{ indices.do({ arg item,i; indices.put(i, item.clip(0, sizes.at(i)-1) ); }); }); ^this.put(indices, val); } post { this.doSimple({ arg item; item.post; " ".postln; }); } postln { if( dimension > 1,{ this.do({ arg item, indices; if( (1+indices.at(0) == sizes.at(0) ),{ item.postln; },{ item.post; " ".post; }); if( ( 1+indices.at(1) == sizes.at(1) ) .and(1+indices.at(0) == sizes.at(0) ), { "\n".post; }); }); },{ this.doSimple({ arg item; item.post; " ".post; }); "\n".post; }); } asArray{ var flatArray; flatArray = Array.new; this.doSimple({ arg item,i; flatArray = flatArray.add(item); }); ^flatArray; } doRow { arg indices, function; ^this.doLine(1, indices, function); } doCol { arg indices, function; ^this.doLine(2, indices, function); } doLine { arg dim, indices, function; ^this.doSome(dim, indices, function); } doSome { arg dims, indices, function; ^this.getSome( dims, indices).do(function); } do { arg function; var dim, indices; dim = dimension; indices = sizes.copy; ^this.prRecDo(indices, dim, function); } // private prRecDo { arg indices, dim, function; if( dim == 0,{ ^function.value( this.at(indices), indices); },{ sizes.at(dim-1).do({ arg pos; var nextPositions; nextPositions = indices.copy.put(dim-1, pos); this.prRecDo(nextPositions, dim-1, function) }); }); } doRowSimple { arg indices, function; ^this.doLineSimple(1, indices, function); } doColSimple { arg indices, function; ^this.doLineSimple(2, indices, function); } doLineSimple { arg dim, indices, function; ^this.doSomeSimple(dim, indices, function); } doSomeSimple { arg dims, indices, function; ^this.getSome( dims, indices).doSimple(function); } doSimple { arg function; ^super.do(function); } // returning new Arrays // flop { arg times = 1; // var newDims, array; // newDims = sizes.rotate(-1*times); // array = ArrayND.new(newDims); // this.do({ arg item, indices; // array.put(indices.rotate(-1*times), item) // }); // ^array; // return a new array // } getDiagonal { var diagonal, count=0; diagonal = ArrayND.new([sizes.minItem]); this.do({ arg item, indices; if( indices.every({arg dim; dim == indices.at(0)}) ,{ diagonal.put(count,item) ; count = count+1; }); }); ^diagonal; } sub { arg remPositions; var sub, count = 0; sub = ArrayND.new(sizes-1); this.do({ arg item, indices; if( indices.any({arg item, i; item == remPositions.at(i) }).not,{ sub.put(count,item) ; count = count+1; }); }); ^sub; } getRow { arg indices; ^this.getLine(1, indices); } getCol { arg indices; ^this.getLine(2, indices); } // even more 2D convenience row { arg row; ^this.getLine(1, row); } col { arg col; ^this.getLine(2, col); } getLine { arg dim, indices; ^this.getSome(dim, indices); } getSome { arg dims, indices; var some, newDims, count = 0, checkPos; // argsize=1 convenience if(indices.size == 0,{indices=[indices]}); if(dims.size == 0,{dims=[dims];}); if(dims.at(0).notNil,{ newDims = dims.collect({ arg dim; sizes.at(dim) }); },{newDims = [1]}); some = ArrayND.new(newDims); this.do({ arg item, positions; checkPos = positions.reject({ arg pos,i; dims.includes(i) }); if( checkPos.every({arg pos, i; pos == indices.at(i) }),{ some.put(count,item) ; count = count+1; }); }); ^some; } collectRow { arg indices, function; ^this.collectLine(1, indices, function); } collectCol { arg indices, function; ^this.collectLine(2, indices, function); } collectLine { arg dim, indices, function; ^this.collectSome(dim, indices, function); } collectSome { arg dims, indices, function; ^this.getSome( dims, indices).collect(function); } collect { arg function; var array; array = ArrayND.new(sizes); this.do({ arg item, indices; array.put(indices, function.value( item, indices) ); }); ^array; } collectRowSimple { arg indices, function; ^this.collectLineSimple(1, indices, function); } collectColSimple { arg indices, function; ^this.collectLineSimple(2, indices, function); } collectLineSimple { arg dim, indices, function; ^this.collectSomeSimple(dim, indices, function); } collectSomeSimple { arg dims, indices, function; ^this.getSome( dims, indices).collectSimple(function); } collectSimple { arg function; var array; array = ArrayND.new(sizes); this.doSimple({ arg item, i; array.put(i, function.value( item, i) ); }); ^array; } // changing Arrays flop { arg times = 1; var newDims, array; array = this.copy; sizes = sizes.rotate(-1*times); array.do({ arg item, indices; this.put(indices.rotate(-1*times), item) }); ^this; } putRow { arg indices, row; ^this.putLine(1, indices, row); } putCol { arg indices, col; ^this.putLine(2, indices, col); } putLine { arg dim, indices, line; ^this.putSome(dim, indices, line); } putSome { arg dims, indices, some; var count = 0, checkPos; // argsize=1 convenience if(indices.size == 0,{indices=[indices]}); if(dims.size == 0,{dims=[dims]}); this.do({ arg item, positions; checkPos = positions.reject({ arg pos,i; dims.includes(i) }); if( checkPos.every({arg pos, i; pos == indices.at(i) }),{ this.put(positions,some.at(count)) ; count = count+1; }); }); ^this; } processRow { arg indices, function; ^this.processLine(1, indices, function); } processCol { arg indices, function; ^this.processLine(2, indices, function); } processLine { arg dim, indices, function; ^this.processSome(dim, indices, function); } processSome { arg dims, indices, function; var count = 0, checkPos; // argsize=1 convenience if(indices.size == 0,{indices=[indices]}); if(dims.size == 0,{dims=[dims]}); this.do({ arg item, positions; checkPos = positions.reject({ arg pos,i; dims.includes(i) }); if( checkPos.every({arg pos, i; pos == indices.at(i) }),{ this.put(positions,function.value( item, positions) ) ; count = count+1; }); }); ^this; } process { arg function; this.do({ arg item, indices; this.put(indices, function.value( item, indices) ); }); } processRowSimple { arg indices, function; ^this.processLineSimple(1, indices, function); } processColSimple { arg indices, function; ^this.processLineSimple(2, indices, function); } processLineSimple { arg dim, indices, function; ^this.processSomeSimple(dim, indices, function); } processSomeSimple { arg dims, indices, function; ^this.putSome( dims, indices, this.collectSomeSimple( dims, indices, function) ); // like this you have a simple index counting through what // you get from a getSome(dims, indices) } // processSomeSimple { arg dims, indices, function; // ^this.putSome( dims, // indices, // this.collectSome( dims, indices, function) // ); // // like this you N-dim indices counting through what // // you get from a getSome(dims, indices) // } processSimple { arg function; this.doSimple({ arg item, i; this.put(i, function.value( item, i) ); }); } // shaping flat { sizes = [this.size]; if( dimension > 0,{dimension = 1}); ^this } flatten{ arg n = 1; var mul; if(n < (dimension-1),{ n.do({ arg i; mul = sizes.pop; sizes.put(sizes.size-1, sizes.at(sizes.size-1)*mul); }); dimension = dimension-n; ^this },{^this.flat}); } flattenTo{ arg dim; var mul; mul = sizes.pop; sizes.put(dim, sizes.at(dim)*mul); if(dimension > 0,{dimension = dimension-1}); } reshape{ arg newShape; var elements = 1; newShape.do({ arg item; elements = item*elements;}); if( elements == this.size,{ this.prReshape(newShape) },{ this.newErrorWindow;error("shapes don't fit in ArrayND::reshape");this.halt }); } prReshape { arg newShape; sizes = newShape; if(dimension > 0,{dimension = newShape.size}); ^this } rotateSome { arg dims, indices, steps=1; var rotor, some; rotor = this.getSome(dims, indices); some = ArrayND.with(rotor.asArray.rotate(steps), rotor.sizes); ^this.putSome(dims, indices, some ); } // math / operators + { arg array; if(array.shape == this.shape,{ ^this.collectSimple({arg item,i; this.at(i) + array.at(i)}); },{ this.newErrorWindow;error("shapes don't fit in ArrayND::+");this.halt }); } - { arg array; if(array.shape == this.shape,{ ^this.collectSimple({arg item,i; this.at(i) - array.at(i)}); },{ this.newErrorWindow;error("shapes down fit in ArrayND::+");this.halt }); } * { arg array; if( array.size == 0,{ ^this.collectSimple({arg item,i; item * array}); }); if( array.size == 1,{ ^this.collectSimple({arg item,i; item * array.at(0)}); }); } == { arg array; if(array.shape == this.shape,{ ^this.every({arg item,i; item == array.at(i)}); },{ ^false}); } ==* { arg array; ^this.every({arg item,i; item == array.at(i)}); } sumAll { var sum = 0; this.doSimple({arg item,i; sum = sum + item}); ^sum } mulElements { arg array2; var result; result = ArrayND.new(sizes); if( this.shape == array2.shape,{ this.doSimple({arg item,i; result.put(i,this.at(i) * array2.at(i) ); }); },{ this.newErrorWindow;error("shapes down fit in ArrayND::mulElements");this.halt }); ^result; } }