pax_global_header00006660000000000000000000000064117214327030014512gustar00rootroot0000000000000052 comment=6b4473e6c0eb11e3c5ff604eb7f157680198ee63 mldemos-0.4.3/000077500000000000000000000000001172143270300131565ustar00rootroot00000000000000mldemos-0.4.3/.gitignore000066400000000000000000000006451172143270300151530ustar00rootroot00000000000000# MLDemos noise last-data.txt *.psd *.sln *.zip # build/debug output */ValgrindOut.xml pluginsDebug/* plugins/* mldemos # osx noise .DS_Store profile # qt noise Makefile* *.pro.user* *.app *.dylib #codeblocks noise *.layout *.depend # xcode noise build/* *.mode1 *.mode1v3 *.mode2v3 *.perspective *.perspectivev3 *.pbxuser *.xcworkspace xcuserdata # svn & cvs .svn CVS # debian build debris /.pc/ # temp files *~ mldemos-0.4.3/Core/000077500000000000000000000000001172143270300140465ustar00rootroot00000000000000mldemos-0.4.3/Core/Core.pro000066400000000000000000000017411172143270300154630ustar00rootroot00000000000000########################### # Configuration # ########################### TEMPLATE = lib QT += svg NAME = Core MLPATH =.. CONFIG += coreLib static include($$MLPATH/MLDemos_variables.pri) win32{ DESTDIR = ../Core } ########################### # Files # ########################### FORMS += expose.ui \ dataImport.ui HEADERS += \ basicMath.h \ canvas.h \ datasetManager.h \ optimization_test_functions.h \ gettimeofday.h \ drawUtils.h \ drawSVG.h \ drawTimer.h \ mymaths.h \ expose.h \ public.h \ parser.h \ roc.h \ types.h \ widget.h \ interfaces.h \ classifier.h \ obstacles.h \ regressor.h \ maximize.h \ dynamical.h \ clusterer.h \ fileUtils.h \ spline.h \ projector.h \ dataImporter.h SOURCES += \ canvas.cpp \ datasetManager.cpp \ drawUtils.cpp \ drawSVG.cpp \ drawTimer.cpp \ mymaths.cpp \ expose.cpp \ roc.cpp \ fileUtils.cpp \ parser.cpp \ widget.cpp \ dataImporter.cpp mldemos-0.4.3/Core/basicMath.h000066400000000000000000000535021172143270300161170ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _BASICMATH_H_ #define _BASICMATH_H_ #include "public.h" #include #include #include #define PIf 3.1415926535897932384626433832795f #ifdef WIN32 #define drand48() (rand()/(float)RAND_MAX) #define srand48(seed) (srand(seed)) #endif /*! * Cubic interpolation class adapted from an algorithm by Marino 'Mutilate' Alge * works with cvVec2 and Vec3 types */ template class CCubic { private: T a, b, c, d; public: /*! Constructor, takes 4 points as input for the interpolation \param x0-x3 the input points for interpolation */ CCubic(T x0, T x1, T x2, T x3) { // a = x1; // b = (x2 - x0)*0.5f; // c = x0 - x1*2.5f + x2*2.0f - x3*0.5f; // d = (x3 - x0)*0.5f - (x2 - x1)*1.5f; a = x1; b = MulS(Sub(x2,x0),0.5f); c = Add(Sub(x0,MulS(x1,2.5f)),Sub(MulS(x2,2.0f),MulS(x3,0.5f))); d = Sub(MulS(Sub(x3,x0),0.5f),MulS(Sub(x2,x1),1.5f)); } /*! The interpolation prediction function \param t the input time \return returns the value expected at time t */ T X(float t) const { //return a + (b + (c + d*t)*t)*t; return Add(a,MulS(Add(b,MulS(Add(c,MulS(d,t)),t)),t)); } /*! All in one interpolation function \param x0-x3 the input points for interpolation \param t the input time \return returns the value expected at time t, using points x0-x3 for interpolation */ static T X(T x0, T x1, T x2, T x3, float t) { //return x1 + ((x2 - x0)*0.5f + (x0 - x1*2.5f + x2*2.0f - x3*0.5f + (x3 - x0)*0.5f - (x2 - x1)*1.5f*t)*t)*t; T asd7 = Sub(x0, MulS(x1,2.5f)); T asd6 = Sub(MulS(x2,2.0f), MulS(x3,0.5f)); T asd5 = Sub(MulS(Sub(x3,x0),0.5f), MulS(Sub(x2,x1),1.5f*t)); T asd4 = Add(asd5,Add(asd6,asd7)); T asd3 = MulS(asd4,t); T asd2 = Add(MulS(Sub(x2,x0),0.5f), asd3); T asd = MulS(asd2,t); return Add(x1, asd); } }; /*! Random Permutations array \param length the length of the output array \param seed random seed (optional) clock used otherwise \return returns an array of indices between 0 and 'length' randomly sorted */ static u32 *randPerm(u32 length, s32 seed=-1) { u32 i=0; u32 *perm = new u32[length]; u32 *usable = new u32[length]; int uLength = length; if(seed != -1) srand(seed); for(int i=0; i0?1:-1) * erftable((int)(min(6.f,abs(x))*100)); // 0:0.01:6 static const float erftable [] = { 0.0000000000000000f, 0.0112834155558496f, 0.0225645746918449f, 0.0338412223417354f, 0.0451111061451247f, 0.0563719777970166f, 0.0676215943933084f, 0.0788577197708907f, 0.0900781258410182f, 0.1012805939146269f, 0.1124629160182849f, 0.1236228961994743f, 0.1347583518199201f, 0.1458671148356958f, 0.1569470330628558f, 0.1679959714273635f, 0.1790118131981057f, 0.1899924612018088f, 0.2009358390186958f, 0.2118398921577497f, 0.2227025892104785f, 0.2335219229821036f, 0.2442959115991287f, 0.2550225995922731f, 0.2657000589537920f, 0.2763263901682369f, 0.2868997232157491f, 0.2974182185470128f, 0.3078800680290340f, 0.3182834958609522f, 0.3286267594591273f, 0.3389081503107902f, 0.3491259947955827f, 0.3592786549743590f, 0.3693645293446587f, 0.3793820535623103f, 0.3893297011286642f, 0.3992059840429992f, 0.4090094534196940f, 0.4187387000697961f, 0.4283923550466685f, 0.4379690901554394f, 0.4474676184260253f, 0.4568866945495403f, 0.4662251152779575f, 0.4754817197869237f, 0.4846553900016797f, 0.4937450508860821f, 0.5027496706947650f, 0.5116682611885233f, 0.5204998778130465f, 0.5292436198411704f, 0.5378986304788544f, 0.5464640969351416f, 0.5549392504563904f, 0.5633233663251089f, 0.5716157638237684f, 0.5798158061639961f, 0.5879229003816007f, 0.5959364971979084f, 0.6038560908479259f, 0.6116812188758802f, 0.6194114618987212f, 0.6270464433381957f, 0.6345858291221413f, 0.6420293273556719f, 0.6493766879629542f, 0.6566277023003051f, 0.6637822027413580f, 0.6708400622350779f, 0.6778011938374186f, 0.6846655502174442f, 0.6914331231387512f, 0.6981039429170445f, 0.7046780778547458f, 0.7111556336535152f, 0.7175367528055909f, 0.7238216139648592f, 0.7300104312985789f, 0.7361034538206912f, 0.7421009647076605f, 0.7480032805977895f, 0.7538107508749625f, 0.7595237569377731f, 0.7651427114549946f, 0.7706680576083524f, 0.7761002683235567f, 0.7814398454905507f, 0.7866873191739325f, 0.7918432468144954f, 0.7969082124228322f, 0.8018828257659413f, 0.8067677215477618f, 0.8115635585845578f, 0.8162710189760625f, 0.8208908072732779f, 0.8254236496438183f, 0.8298702930356671f, 0.8342315043402079f, 0.8385080695553697f, 0.8427007929497148f, 0.8468104962282766f, 0.8508380177009420f, 0.8547842114541484f, 0.8586499465266515f, 0.8624361060900967f, 0.8661435866351080f, 0.8697732971635868f, 0.8733261583878896f, 0.8768031019375383f, 0.8802050695740817f, 0.8835330124147180f, 0.8867878901652547f, 0.8899706703629624f, 0.8930823276298567f, 0.8961238429369151f, 0.8990962028797120f, 0.9020003989659357f, 0.9048374269152169f, 0.9076082859716850f, 0.9103139782296355f, 0.9129555079726694f, 0.9155338810266469f, 0.9180501041267614f, 0.9205051842990297f, 0.9229001282564582f, 0.9252359418101295f, 0.9275136292954247f, 0.9297341930135782f, 0.9318986326887336f, 0.9340079449406524f, 0.9360631227731995f, 0.9380651550787114f, 0.9400150261583302f, 0.9419137152583653f, 0.9437621961227241f, 0.9455614365614331f, 0.9473123980352520f, 0.9490160352563626f, 0.9506732958050965f, 0.9522851197626489f, 0.9538524393597054f, 0.9553761786408961f, 0.9568572531449688f, 0.9582965696005648f, 0.9596950256374592f, 0.9610535095131181f, 0.9623728998544057f, 0.9636540654142689f, 0.9648978648432043f, 0.9661051464753108f, 0.9672767481287117f, 0.9684134969201232f, 0.9695162090933357f, 0.9705856898613637f, 0.9716227332620125f, 0.9726281220266002f, 0.9736026274615670f, 0.9745470093426969f, 0.9754620158216676f, 0.9763483833446440f, 0.9772068365826185f, 0.9780380883732035f, 0.9788428396735702f, 0.9796217795242320f, 0.9803755850233603f, 0.9811049213113221f, 0.9818104415651265f, 0.9824927870024649f, 0.9831525868950262f, 0.9837904585907746f, 0.9844070075448683f, 0.9850028273589058f, 0.9855784998281805f, 0.9861345949966329f, 0.9866716712191824f, 0.9871902752311301f, 0.9876909422243223f, 0.9881741959297683f, 0.9886405487064082f, 0.9890905016357308f, 0.9895245446219444f, 0.9899431564974077f, 0.9903468051330306f, 0.9907359475533626f, 0.9911110300560857f, 0.9914724883356396f, 0.9918207476107068f, 0.9921562227552937f, 0.9924793184331480f, 0.9927904292352574f, 0.9930899398201836f, 0.9933782250569847f, 0.9936556501704964f, 0.9939225708887325f, 0.9941793335921891f, 0.9944262754648279f, 0.9946637246465300f, 0.9948920003868136f, 0.9951114131996171f, 0.9953222650189527f, 0.9955248493552482f, 0.9957194514521921f, 0.9959063484439121f, 0.9960858095123195f, 0.9962580960444569f, 0.9964234617896959f, 0.9965821530166383f, 0.9967344086695764f, 0.9968804605243777f, 0.9970205333436670f, 0.9971548450311778f, 0.9972836067851606f, 0.9974070232507333f, 0.9975252926710697f, 0.9976386070373253f, 0.9977471522372077f, 0.9978511082021002f, 0.9979506490526588f, 0.9980459432428015f, 0.9981371537020181f, 0.9982244379759344f, 0.9983079483650648f, 0.9983878320616981f, 0.9984642312848625f, 0.9985372834133188f, 0.9986071211165417f, 0.9986738724836455f, 0.9987376611502190f, 0.9987986064230412f, 0.9988568234026434f, 0.9989124231037001f, 0.9989655125732240f, 0.9990161950065498f, 0.9990645698610920f, 0.9991107329678676f, 0.9991547766407751f, 0.9991967897836264f, 0.9992368579949287f, 0.9992750636704192f, 0.9993114861033550f, 0.9993462015825647f, 0.9993792834882711f, 0.9994108023856942f, 0.9994408261164486f, 0.9994694198877490f, 0.9994966463594419f, 0.9995225657288811f, 0.9995472358136659f, 0.9995707121322661f, 0.9995930479825550f, 0.9996142945182758f, 0.9996345008234653f, 0.9996537139848649f, 0.9996719791623431f, 0.9996893396573607f, 0.9997058369795080f, 0.9997215109111428f, 0.9997363995701628f, 0.9997505394709432f, 0.9997639655834707f, 0.9997767113907082f, 0.9997888089442237f, 0.9998002889181156f, 0.9998111806612684f, 0.9998215122479760f, 0.9998313105269614f, 0.9998406011688324f, 0.9998494087120056f, 0.9998577566071316f, 0.9998656672600594f, 0.9998731620733716f, 0.9998802614865254f, 0.9998869850146334f, 0.9998933512859194f, 0.9998993780778804f, 0.9999050823521898f, 0.9999104802883753f, 0.9999155873163016f, 0.9999204181474947f, 0.9999249868053346f, 0.9999293066541523f, 0.9999333904272598f, 0.9999372502539452f, 0.9999408976854610f, 0.9999443437200386f, 0.9999475988269556f, 0.9999506729696857f, 0.9999535756281590f, 0.9999563158201617f, 0.9999589021219005f, 0.9999613426877595f, 0.9999636452692755f, 0.9999658172333573f, 0.9999678655797740f, 0.9999697969579359f, 0.9999716176829931f, 0.9999733337512747f, 0.9999749508550908f, 0.9999764743969193f, 0.9999779095030015f, 0.9999792610363629f, 0.9999805336092855f, 0.9999817315952467f, 0.9999828591403461f, 0.9999839201742398f, 0.9999849184206001f, 0.9999858574071167f, 0.9999867404750594f, 0.9999875707884177f, 0.9999883513426329f, 0.9999890849729398f, 0.9999897743623336f, 0.9999904220491747f, 0.9999910304344468f, 0.9999916017886847f, 0.9999921382585810f, 0.9999926418732865f, 0.9999931145504183f, 0.9999935581017863f, 0.9999939742388482f, 0.9999943645779092f, 0.9999947306450711f, 0.9999950738809456f, 0.9999953956451422f, 0.9999956972205364f, 0.9999959798173321f, 0.9999962445769250f, 0.9999964925755764f, 0.9999967248279045f, 0.9999969422902035f, 0.9999971458635975f, 0.9999973363970345f, 0.9999975146901312f, 0.9999976814958739f, 0.9999978375231799f, 0.9999979834393308f, 0.9999981198722784f, 0.9999982474128331f, 0.9999983666167385f, 0.9999984780066371f, 0.9999985820739346f, 0.9999986792805644f, 0.9999987700606605f, 0.9999988548221410f, 0.9999989339482065f, 0.9999990077987595f, 0.9999990767117464f, 0.9999991410044279f, 0.9999992009745795f, 0.9999992569016276f, 0.9999993090477226f, 0.9999993576587528f, 0.9999994029653040f, 0.9999994451835634f, 0.9999994845161754f, 0.9999995211530479f, 0.9999995552721144f, 0.9999995870400529f, 0.9999996166129631f, 0.9999996441370069f, 0.9999996697490110f, 0.9999996935770344f, 0.9999997157409060f, 0.9999997363527273f, 0.9999997555173494f, 0.9999997733328196f, 0.9999997898908039f, 0.9999998052769828f, 0.9999998195714259f, 0.9999998328489421f, 0.9999998451794108f, 0.9999998566280922f, 0.9999998672559198f, 0.9999998771197746f, 0.9999998862727435f, 0.9999998947643614f, 0.9999999026408388f, 0.9999999099452765f, 0.9999999167178646f, 0.9999999229960725f, 0.9999999288148247f, 0.9999999342066670f, 0.9999999392019217f, 0.9999999438288334f, 0.9999999481137065f, 0.9999999520810322f, 0.9999999557536089f, 0.9999999591526549f, 0.9999999622979134f, 0.9999999652077514f, 0.9999999678992515f, 0.9999999703882987f, 0.9999999726896611f, 0.9999999748170654f, 0.9999999767832677f, 0.9999999786001196f, 0.9999999802786297f, 0.9999999818290218f, 0.9999999832607887f, 0.9999999845827421f, 0.9999999858030606f, 0.9999999869293328f, 0.9999999879685986f, 0.9999999889273877f, 0.9999999898117551f, 0.9999999906273142f, 0.9999999913792682f, 0.9999999920724392f, 0.9999999927112944f, 0.9999999932999724f, 0.9999999938423057f, 0.9999999943418427f, 0.9999999948018690f, 0.9999999952254246f, 0.9999999956153229f, 0.9999999959741669f, 0.9999999963043638f, 0.9999999966081397f, 0.9999999968875528f, 0.9999999971445058f, 0.9999999973807567f, 0.9999999975979301f, 0.9999999977975265f, 0.9999999979809319f, 0.9999999981494259f, 0.9999999983041898f, 0.9999999984463144f, 0.9999999985768053f, 0.9999999986965913f, 0.9999999988065282f, 0.9999999989074059f, 0.9999999989999523f, 0.9999999990848385f, 0.9999999991626829f, 0.9999999992340556f, 0.9999999992994814f, 0.9999999993594437f, 0.9999999994143880f, 0.9999999994647240f, 0.9999999995108290f, 0.9999999995530502f, 0.9999999995917070f, 0.9999999996270934f, 0.9999999996594795f, 0.9999999996891137f, 0.9999999997162244f, 0.9999999997410216f, 0.9999999997636982f, 0.9999999997844314f, 0.9999999998033839f, 0.9999999998207052f, 0.9999999998365327f, 0.9999999998509920f, 0.9999999998641989f, 0.9999999998762595f, 0.9999999998872711f, 0.9999999998973228f, 0.9999999999064966f, 0.9999999999148674f, 0.9999999999225040f, 0.9999999999294694f, 0.9999999999358213f, 0.9999999999416126f, 0.9999999999468917f, 0.9999999999517030f, 0.9999999999560869f, 0.9999999999600808f, 0.9999999999637186f, 0.9999999999670313f, 0.9999999999700474f, 0.9999999999727929f, 0.9999999999752915f, 0.9999999999775653f, 0.9999999999796336f, 0.9999999999815150f, 0.9999999999832258f, 0.9999999999847813f, 0.9999999999861953f, 0.9999999999874802f, 0.9999999999886479f, 0.9999999999897087f, 0.9999999999906721f, 0.9999999999915470f, 0.9999999999923415f, 0.9999999999930624f, 0.9999999999937168f, 0.9999999999943107f, 0.9999999999948495f, 0.9999999999953380f, 0.9999999999957810f, 0.9999999999961828f, 0.9999999999965470f, 0.9999999999968769f, 0.9999999999971760f, 0.9999999999974469f, 0.9999999999976923f, 0.9999999999979145f, 0.9999999999981156f, 0.9999999999982978f, 0.9999999999984626f, 0.9999999999986117f, 0.9999999999987466f, 0.9999999999988686f, 0.9999999999989789f, 0.9999999999990787f, 0.9999999999991689f, 0.9999999999992504f, 0.9999999999993240f, 0.9999999999993905f, 0.9999999999994507f, 0.9999999999995048f, 0.9999999999995539f, 0.9999999999995981f, 0.9999999999996381f, 0.9999999999996740f, 0.9999999999997065f, 0.9999999999997358f, 0.9999999999997622f, 0.9999999999997861f, 0.9999999999998075f, 0.9999999999998268f, 0.9999999999998444f, 0.9999999999998600f, 0.9999999999998741f, 0.9999999999998870f, 0.9999999999998983f, 0.9999999999999087f, 0.9999999999999181f, 0.9999999999999263f, 0.9999999999999338f, 0.9999999999999407f, 0.9999999999999467f, 0.9999999999999523f, 0.9999999999999572f, 0.9999999999999616f, 0.9999999999999655f, 0.9999999999999691f, 0.9999999999999722f, 0.9999999999999751f, 0.9999999999999778f, 0.9999999999999800f, 0.9999999999999821f, 0.9999999999999840f, 0.9999999999999857f, 0.9999999999999871f, 0.9999999999999885f, 0.9999999999999898f, 0.9999999999999908f, 0.9999999999999918f, 0.9999999999999927f, 0.9999999999999933f, 0.9999999999999941f, 0.9999999999999947f, 0.9999999999999953f, 0.9999999999999958f, 0.9999999999999962f, 0.9999999999999967f, 0.9999999999999970f, 0.9999999999999973f, 0.9999999999999976f, 0.9999999999999979f, 0.9999999999999981f, 0.9999999999999983f, 0.9999999999999985f, 0.9999999999999987f, 0.9999999999999988f, 0.9999999999999989f, 0.9999999999999991f, 0.9999999999999991f, 0.9999999999999992f, 0.9999999999999993f, 0.9999999999999993f, 0.9999999999999994f, 0.9999999999999996f, 0.9999999999999996f, 0.9999999999999996f, 0.9999999999999997f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999998f, 0.9999999999999999f, 0.9999999999999999f, 0.9999999999999999f, 0.9999999999999999f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f, 1.0000000000000000f }; /*! Gaussian Error Function */ static float erf(const float x) { if(x>0) return erftable[(int)(min(6.f,x)*100)]; return -erftable[(int)(min(6.f,-x)*100)]; } enum distEnum {DIST_EUCLIDEAN, DIST_MANHATTAN, DIST_INFINITE} ; inline float Distance(float *a, float *b, u32 dim, distEnum metric) { float dist = 0; switch(metric) { case DIST_EUCLIDEAN: FOR(i, dim) dist += powf(a[i]-b[i],2); dist = sqrtf(dist); break; case DIST_MANHATTAN: FOR(i, dim) dist += (float)abs((double)a[i]-(double)b[i]); break; case DIST_INFINITE: FOR(i, dim) dist = max(dist, (float)abs((double)a[i]-(double)b[i])); break; } return dist; } /** * Performs soft-kmeans clustering. The number of clusters is inferred from the dimension of means * it is advisable to normalize the data in order to avoid numerical problems due to the negative exp function * \param points the input points * \param means, the starting cluster positions * \param dim, the dimension of the point data * \param beta, the stiffness of the soft-kmeans boundary * \return returns the weights for each points for each cluster * */ inline std::vector SoftKMeans(const std::vector points, std::vector *means, unsigned int dim, float beta) { unsigned int clusters = means->size(); std::vector weights; for (unsigned int i=0; i < points.size(); i++) { weights.push_back(fvec()); for (unsigned int j=0; j < clusters; j++) weights[i].push_back(0); } fvec distances; for (unsigned int i=0; i < clusters; i++) distances.push_back(0); // Expectation Step for (unsigned int i=0; i < points.size(); i++) { float distanceSum = 0; for (unsigned int j=0; j < clusters; j++) { distances[j] = expf(-beta*Distance(points[i], (*means)[j], dim, DIST_EUCLIDEAN)); distanceSum += distances[j]; } for (unsigned int j=0; j < clusters; j++) { weights[i][j] = distances[j] / distanceSum; } } // Maximization Step fvec perCluster; for (unsigned int i=0; i < clusters; i++) { for (unsigned int j=0; j < dim; j++) (*means)[i][j] = 0; perCluster.push_back(0); } for (unsigned int i=0; i < points.size(); i++) { for (unsigned int j=0; j < clusters; j++) { for (unsigned int k=0; k < dim; k++) { (*means)[j][k] += points[i][k] * weights[i][j]; } perCluster[j] += weights[i][j]; } } for (unsigned int i=0; i < clusters; i++) { if(perCluster[i] != 0) { for (unsigned int j=0; j < dim; j++) { (*means)[i][j] /= perCluster[i]; } } } return weights; } static std::vector Quartiles(std::vector srcdata) { std::vector quartiles; if(!srcdata.size()) { quartiles.resize(5,0); return quartiles; } // we take out all non-zero elements std::vector data; FOR(i, srcdata.size()) if(srcdata[i] != 0) data.push_back(srcdata[i]); if(!data.size()) { quartiles.resize(5,0); return quartiles; } if(data.size()==1) { quartiles.resize(5,data[0]); return quartiles; } float mean = 0; float sigma = 0; FOR(i, data.size()) mean += data[i] / data.size(); FOR(i, data.size()) sigma += powf(data[i]-mean,2); sigma = sqrtf(sigma/data.size()); std::vector outliers; std::vector sorted; if(sigma==0) { sorted = data; } else { // we look for outliers using the 3*sigma rule FOR(i, data.size()) { if (data[i] - mean < 3*sigma) sorted.push_back(data[i]); else outliers.push_back(data[i]); } } if(!sorted.size()) { quartiles.resize(5,0); return quartiles; } sort(sorted.begin(), sorted.end()); int count = sorted.size(); int half = count/2; float bottom = sorted[0]; float top = sorted[sorted.size()-1]; float median = count%2 ? sorted[half] : (sorted[half] + sorted[half - 1])/2; float quartLow, quartHi; if(count < 4) { quartLow = bottom; quartHi = top; } else { quartLow = half%2 ? sorted[half/2] : (sorted[half/2] + sorted[half/2 - 1])/2; quartHi = half%2 ? sorted[half*3/2] : (sorted[half*3/2] + sorted[half*3/2 - 1])/2; } quartiles.push_back(bottom); quartiles.push_back(quartLow); quartiles.push_back(median); quartiles.push_back(quartHi); quartiles.push_back(top); return quartiles; } static std::vector MeanStd(std::vector srcdata) { std::vector results; results.resize(2,0); if(!srcdata.size()) { return results; } if(srcdata.size() == 1) { results[0] = srcdata[0]; results[1] = 0; return results; } float mean = 0; float stdev = 0; FOR(i, srcdata.size()) { mean += srcdata[i]; } mean /= srcdata.size(); FOR(i, srcdata.size()) { stdev += (srcdata[i]-mean)*(srcdata[i]-mean); } stdev = sqrtf(stdev); results[0] = mean; results[1] = stdev; return results; } #endif // _BASICMATH_H_ mldemos-0.4.3/Core/canvas.cpp000066400000000000000000001251111172143270300160260ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include #include #include #include #include #include #include #include #include "expose.h" #include "public.h" #include "basicMath.h" #include "canvas.h" #include "drawUtils.h" using namespace std; //DatasetManager Canvas::data; bool Canvas::bCrossesAsDots = true; Canvas::Canvas(QWidget *parent) : QWidget(parent), bDisplayMap(false), bDisplayInfo(false), bDisplaySingle(false), bDisplaySamples(true), bDisplayTrajectories(true), bDisplayTimeSeries(true), bDisplayLearned(true), bDisplayGrid(true), crosshair(QPainterPath()), bShowCrosshair(false), bNewCrosshair(true), trajectoryCenterType(0), trajectoryResampleType(1), trajectoryResampleCount(100), liveTrajectory(vector()), centers(map()), drawnSamples(0), drawnTrajectories(0), drawnTimeseries(0), mouseAnchor(QPoint(-1,-1)), bDrawing(false), zoom(1.f), zooms(2,1.f), center(2,0), xIndex(0), yIndex(1), zIndex(-1), canvasType(0), data(new DatasetManager()) { resize(640,480); setAcceptDrops(true); setMouseTracking(true); setCursor(Qt::CrossCursor); setBackgroundRole(QPalette::Base); setMouseTracking(true); QPalette p(palette()); p.setColor(backgroundRole(), Qt::white); setPalette(p); show(); } Canvas::~Canvas() { if(data) DEL(data); } void Canvas::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("text/plain")) event->acceptProposedAction(); } void Canvas::dropEvent(QDropEvent *event) { if(event->mimeData()->text() == "Target") { QPointF position = event->pos(); //qDebug() << "Dropping Target at coordinates: " << position; targets.push_back(toSampleCoords(position.x(), position.y())); } else if(event->mimeData()->text() == "Gaussian") { QPointF position = event->pos(); double variance = event->mimeData()->colorData().toDouble(); PaintGaussian(position, variance); } else if(event->mimeData()->text() == "Gradient") { QPointF position = event->pos(); PaintGradient(position); } event->acceptProposedAction(); } void Canvas::SetConfidenceMap(QImage image) { maps.confidence = QPixmap::fromImage(image); repaint(); } void Canvas::SetModelImage(QImage image) { maps.model = QPixmap::fromImage(image); repaint(); } void Canvas::SetCanvasType(int type) { if(canvasType || type) { maps.model = QPixmap(); maps.info = QPixmap(); } maps.samples = QPixmap(); maps.trajectories = QPixmap(); maps.grid = QPixmap(); canvasType = type; ResetSamples(); bNewCrosshair = true; } void Canvas::PaintStandard(QPainter &painter, bool bSvg) { painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Qt::white); painter.fillRect(geometry(),Qt::white); if(bDisplayMap) { if(!maps.confidence.isNull()) painter.drawPixmap(geometry(), maps.confidence); } painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); if(bDisplaySamples) { DrawRewards(); if(!maps.reward.isNull()) { painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.reward); } if(bSvg) DrawSamples(painter); else { DrawSamples(); painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.samples); } DrawObstacles(painter); //painter.drawPixmap(geometry(), maps.obstacles); } if(bDisplayTrajectories) { if(bSvg) { DrawTrajectories(painter); } else { DrawTrajectories(); painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.trajectories); } if(targets.size()) DrawTargets(painter); } if(bDisplayTimeSeries) { if(bSvg) { } else { DrawTimeseries(); painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.timeseries); } } if(!bSvg && bDisplayLearned) { if(maps.model.isNull()) { int w = width(); int h = height(); maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.model.setMask(bitmap); maps.model.fill(Qt::transparent); QPainter painter(&maps.model); DrawSampleColors(painter); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.model); } if(!bSvg && bDisplayInfo && !maps.info.isNull()) { painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.info); } if(!bSvg && bShowCrosshair) { if(bNewCrosshair) emit DrawCrosshair(); painter.setBackgroundMode(Qt::TransparentMode); painter.drawPath(crosshair.translated(mouse)); if(liveTrajectory.size()) DrawLiveTrajectory(painter); } if(bDisplayGrid) { if(bSvg) { } else { if(maps.grid.isNull()) RedrawAxes(); painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.grid); } } } void Canvas::PaintMultivariate(QPainter &painter, int type) { painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Qt::white); painter.fillRect(geometry(),Qt::white); std::pair bounds = data->GetBounds(); if(bDisplaySamples) { if(maps.samples.isNull()) { int w = width(); int h = height(); maps.samples = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.samples.setMask(bitmap); maps.samples.fill(Qt::transparent); Expose::DrawData(maps.samples, data->GetSamples(), data->GetLabels(), data->GetFlags(), type, data->bProjected, dimNames, bounds); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.samples); } if(bDisplayTrajectories && (type != 1 && type != 3)) { if(maps.trajectories.isNull()) { int w = width(); int h = height(); maps.trajectories = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.trajectories.setMask(bitmap); maps.trajectories.fill(Qt::transparent); Expose::DrawTrajectories(maps.trajectories, data->GetTrajectories(trajectoryResampleType, trajectoryResampleCount, trajectoryCenterType, 0.1, true), data->GetLabels(), type, 0, bounds); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.trajectories); } if(bDisplayLearned) { if(maps.model.isNull() && sampleColors.size()) { int w = width(); int h = height(); maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.model.setMask(bitmap); maps.model.fill(Qt::transparent); Expose::DrawData(maps.model, data->GetSamples(), sampleColors, data->GetFlags(), type, data->bProjected, true, dimNames); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.model); } if(bDisplayInfo && !maps.info.isNull()) { //painter.setBackgroundMode(Qt::TransparentMode); //painter.drawPixmap(geometry(), maps.info); } if(bDisplayGrid) { if(maps.grid.isNull()) { } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.grid); } } void Canvas::PaintVariable(QPainter &painter, int type, fvec params) { painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Qt::white); painter.fillRect(geometry(),Qt::white); if(maps.samples.isNull()) { int w = width(); int h = height(); maps.samples = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.samples.setMask(bitmap); maps.samples.fill(Qt::transparent); Expose::DrawVariableData(maps.samples, data->GetSamples(), data->GetLabels(), type, params, data->bProjected); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.samples); if(maps.trajectories.isNull()) { int w = width(); int h = height(); maps.trajectories = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.trajectories.setMask(bitmap); maps.trajectories.fill(Qt::transparent); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.trajectories); if(maps.model.isNull() && sampleColors.size()) { int w = width(); int h = height(); maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.model.setMask(bitmap); maps.model.fill(Qt::transparent); Expose::DrawVariableData(maps.model, data->GetSamples(), sampleColors, type, params, data->bProjected); } painter.setBackgroundMode(Qt::TransparentMode); painter.drawPixmap(geometry(), maps.model); } void Canvas::paintEvent(QPaintEvent *event) { if(bDrawing) return; bDrawing = true; QPainter painter(this); if(!canvasType) PaintStandard(painter); else if(canvasType <= 4) PaintMultivariate(painter, canvasType-1); else { fvec params; params.push_back(xIndex); params.push_back(yIndex); params.push_back(zIndex); PaintVariable(painter, canvasType-5, params); } bDrawing = false; } QPointF Canvas::toCanvasCoords(fvec sample) { if(!sample.size()) return QPointF(0,0); if(sample.size() < center.size()) sample.resize(center.size()); //else if(sample.size() > center.size()) center = fvec(sample.size(), 0); sample -= center; QPointF point(sample[xIndex]*(zoom*zooms[xIndex]*height()),sample[yIndex]*(zoom*zooms[yIndex]*height())); point += QPointF(width()/2, height()/2); return point; } QPointF Canvas::toCanvas(fVec sample) { sample -= center; QPointF point(sample[xIndex]*(zoom*zooms[xIndex]*height()),sample[yIndex]*(zoom*zooms[yIndex]*height())); point += QPointF(width()/2, height()/2); return point; } QPointF Canvas::toCanvasCoords(float x, float y) { x -= center[xIndex]; y -= center[yIndex]; QPointF point(x*(zoom*zooms[xIndex]*height()),y*(zoom*zooms[yIndex]*height())); point += QPointF(width()/2, height()/2); return point; } fvec Canvas::fromCanvas(QPointF point) { int dim = data->GetDimCount(); fvec sample(dim); point -= QPointF(width()/2.f,height()/2.f); sample[xIndex] = point.x()/(zoom*zooms[xIndex]*height()); sample[yIndex] = point.y()/(zoom*zooms[yIndex]*height()); sample += center; return sample; } fvec Canvas::fromCanvas(float x, float y) { int dim = data->GetDimCount(); fvec sample(dim); x -= width()/2.f; y -= height()/2.f; sample[xIndex] = x/(zoom*zooms[xIndex]*height()); sample[yIndex] = y/(zoom*zooms[yIndex]*height()); sample += center; return sample; } fvec Canvas::toSampleCoords(QPointF point) { int dim = data->GetDimCount(); fvec sample(dim); point -= QPointF(width()/2.f,height()/2.f); sample[xIndex] = point.x()/(zoom*zooms[xIndex]*height()); sample[yIndex] = point.y()/(zoom*zooms[yIndex]*height()); sample += center; return sample; } fvec Canvas::toSampleCoords(float x, float y) { int dim = data->GetDimCount(); fvec sample(dim); x -= width()/2.f; y -= height()/2.f; sample[xIndex] = x/(zoom*zooms[xIndex]*height()); sample[yIndex] = y/(zoom*zooms[yIndex]*height()); sample += center; return sample; } fvec Canvas::canvasTopLeft() { return toSampleCoords(0,0); } fvec Canvas::canvasBottomRight() { return toSampleCoords(width()-1,height()-1); } QRectF Canvas::canvasRect() { fvec tl = canvasTopLeft(); fvec br = canvasBottomRight(); return QRectF(tl[xIndex], tl[yIndex], (br-tl)[xIndex], (br-tl)[yIndex]); } void Canvas::SetZoom(float zoom) { if(this->zoom == zoom) return; this->zoom = zoom; // int dim = data->GetDimCount(); // zooms = fvec(dim,1.f); maps.grid = QPixmap(); maps.model = QPixmap(); maps.confidence = QPixmap(); //maps.reward = QPixmap(); maps.info = QPixmap(); ResetSamples(); bNewCrosshair = true; //repaint(); } void Canvas::SetZoom(fvec zooms) { if(this->zooms == zooms) return; this->zooms = zooms; zoom = 1.f; maps.grid = QPixmap(); maps.model = QPixmap(); maps.confidence = QPixmap(); //maps.reward = QPixmap(); maps.info = QPixmap(); ResetSamples(); bNewCrosshair = true; //repaint(); } void Canvas::SetCenter(fvec center) { if(this->center == center) return; this->center = center; maps.grid = QPixmap(); maps.model = QPixmap(); maps.confidence = QPixmap(); //maps.reward = QPixmap(); maps.info = QPixmap(); ResetSamples(); bNewCrosshair = true; //repaint(); } void Canvas::SetDim(int xIndex, int yIndex, int zIndex) { bool bChanged = false; if(this->xIndex != xIndex) { bChanged = true; this->xIndex = xIndex; } if(this->yIndex != yIndex) { bChanged = true; this->yIndex = yIndex; } this->zIndex = zIndex; if(bChanged) { maps.grid = QPixmap(); maps.model = QPixmap(); maps.confidence = QPixmap(); //maps.reward = QPixmap(); maps.info = QPixmap(); ResetSamples(); bNewCrosshair = true; //repaint(); } } void Canvas::FitToData() { if(!data->GetCount() && !data->GetTimeSeries().size()) { center = fvec(2,0); SetZoom(1); //qDebug() << "nothing to fit"; return; } int dim = data->GetDimCount(); center = fvec(dim,0); //qDebug() << "fit to data, dim: " << dim; // we go through all the data and find the boundaries std::pair bounds = data->GetBounds(); fvec mins = bounds.first, maxes = bounds.second; vector samples = data->GetSamples(); vector& series = data->GetTimeSeries(); FOR(i, series.size()) { TimeSerie& serie = series[i]; mins[0] = 0; maxes[0] = 1; center[0] = 0.5f; FOR(j, serie.size()) { int dim = serie[j].size(); FOR(d,dim) { if(mins[d+1] > serie[j][d]) mins[d+1] = serie[j][d]; if(maxes[d+1] < serie[j][d]) maxes[d+1] = serie[j][d]; } } } fvec diff = maxes - mins; center = mins + diff/2; /* float diffX = diff[xIndex]*1.04; // add a small margin float diffY = diff[yIndex]*1.04; // add a small margin float aspectRatio = width() / (float)height(); diffX /= aspectRatio; SetZoom(min(1/diffY,1/diffX)); */ zooms = fvec(dim, 1.f); FOR(d, dim) zooms[d] = 1.f / diff[d]; SetZoom(1.f); } void Canvas::DrawAxes(QPainter &painter) { int w = width(); int h = height(); // we find out how 'big' the space is QRectF bounding = canvasRect(); // we round up the size to the closest decimal float scale = bounding.height(); if(scale <= 1e-10) return; float mult = 1; if(scale > 10) { while(scale / mult > 10 && mult != 0) mult *= 2.5f; // we want at most 10 lines to draw } else { while(scale / mult < 5 && mult != 0) mult /= 2.f; // we want at least 5 lines to draw } if(mult == 0) mult = 1; // we now have the measure of the ticks, we can draw this painter.setRenderHint(QPainter::TextAntialiasing); painter.setFont(QFont("Lucida Grande", 9)); for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult) { float canvasX = toCanvasCoords(x,0).x(); if(canvasX < 0 || canvasX > w) continue; painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine)); painter.drawLine(canvasX, 0, canvasX, h); painter.setPen(QPen(Qt::black, 0.5)); painter.drawText(canvasX, h-5, QString("%1").arg((int)(x/mult)*mult)); } // we now have the measure of the ticks, we can draw this for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult) { float canvasY = toCanvasCoords(0,y).y(); if(canvasY < 0 || canvasY > w) continue; painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine)); painter.drawLine(0, canvasY, w, canvasY); painter.setPen(QPen(Qt::black, 0.5)); painter.drawText(2, canvasY, QString("%1").arg((int)(y/mult)*mult)); } } void Canvas::RedrawAxes() { int w = width(); int h = height(); maps.grid = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.grid.setMask(bitmap); maps.grid.fill(Qt::transparent); QPainter painter(&maps.grid); DrawAxes(painter); } void Canvas::DrawSamples(QPainter &painter) { int radius = 10; painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing); for(int i=0; iGetCount(); i++) { if(data->GetFlag(i) == _TRAJ) continue; int label = data->GetLabel(i); QPointF point = toCanvasCoords(data->GetSample(i)); Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label); } } void Canvas::DrawSampleColors(QPainter &painter) { int radius = 10; painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing); for(int i=0; iGetCount(); i++) { if(i >= sampleColors.size()) continue; QColor color = sampleColors[i]; QPointF point = toCanvasCoords(data->GetSample(i)); painter.setBrush(color); painter.setPen(Qt::black); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); } } void Canvas::DrawSamples() { int radius = 10; if(!data->GetCount()) { int w = width(); int h = height(); maps.samples = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.samples.setMask(bitmap); maps.samples.fill(Qt::transparent); drawnSamples = 0; return; } if(drawnSamples == data->GetCount()) return; if(drawnSamples > data->GetCount()) drawnSamples = 0; if(!drawnSamples || maps.samples.isNull()) { int w = width(); int h = height(); maps.samples = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.samples.setMask(bitmap); maps.samples.fill(Qt::transparent); drawnSamples = 0; } QPainter painter(&maps.samples); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing); for(int i=drawnSamples; iGetCount(); i++) { if(data->GetFlag(i) == _TRAJ) continue; int label = data->GetLabel(i); fvec sample = data->GetSample(i); QPointF point = toCanvasCoords(sample); Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label); } drawnSamples = data->GetCount(); } void Canvas::DrawTargets(QPainter &painter) { painter.setRenderHint(QPainter::Antialiasing, true); FOR(i, targets.size()) { QPointF point = toCanvasCoords(targets[i]); QPointF delta1 = QPointF(1,1); QPointF delta2 = QPointF(1,-1); painter.setBrush(Qt::NoBrush); painter.setPen(QPen(Qt::black, 1.5)); int r = 8, p = 2; painter.drawEllipse(point,r,r); painter.drawLine(point+delta1*r, point+delta1*r+delta1*p); painter.drawLine(point-delta1*r, point-delta1*r-delta1*p); painter.drawLine(point+delta2*r, point+delta2*r+delta2*p); painter.drawLine(point-delta2*r, point-delta2*r-delta2*p); } } QPainterPath Canvas::DrawObstacle(Obstacle o) { QPointF point; float aX = o.axes[0]; float aY = o.axes[1]; float angle = o.angle; float pX = o.power[0]; float pY = o.power[1]; QPainterPath obstaclePath; QPointF firstPoint; // first we draw the obstacle for(float theta=-PIf; theta < PIf + 0.1; theta += 0.1f) { float X, Y; X = aX * cosf(theta); //Y = aY * sinf(theta); Y = aY * (theta>=0?1.f:-1.f) * powf((1-powf(cosf(theta),2.f*pX)),1./(2*pY)); float RX = + X * cosf(angle) - Y * sinf(angle); float RY = + X * sinf(angle) + Y * cosf(angle); point = QPointF(RX*(zoom*zooms[xIndex]*height()),RY*(zoom*zooms[yIndex]*height())); if(theta==-PIf) { firstPoint = point; obstaclePath.moveTo(point); continue; } obstaclePath.lineTo(point); } obstaclePath.lineTo(firstPoint); return obstaclePath; } void Canvas::DrawObstacles(QPainter &painter) { painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); // we draw the obstacles if(!data->GetObstacles().size()) return; QList paths; QList safeties; FOR(i, data->GetObstacles().size()) { QPainterPath obstaclePath = DrawObstacle(data->GetObstacle(i)); obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center)); paths.push_back(obstaclePath); obstaclePath = DrawObstacle(data->GetObstacle(i)); QMatrix scalingMatrix; QPointF t = toCanvasCoords(data->GetObstacle(i).center); scalingMatrix.scale(data->GetObstacle(i).repulsion[0], data->GetObstacle(i).repulsion[1]); obstaclePath = scalingMatrix.map(obstaclePath); obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center)); safeties.push_back(obstaclePath); } FOR(i, paths.size()) { painter.setBrush(Qt::white); painter.setPen(QPen(Qt::black, 1,Qt::SolidLine)); painter.drawPath(paths[i]); painter.setBrush(Qt::NoBrush); painter.setPen(QPen(Qt::black, 1,Qt::DotLine)); painter.drawPath(safeties[i]); } } void Canvas::DrawObstacles() { int w = width(); int h = height(); maps.obstacles = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.obstacles.setMask(bitmap); maps.obstacles.fill(Qt::transparent); QPainter painter(&maps.obstacles); DrawObstacles(painter); } void Canvas::DrawRewards() { return; int w = width(); int h = height(); maps.reward= QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.reward.setMask(bitmap); maps.reward.fill(Qt::transparent); if(!data->GetReward()->rewards) return; QPainter painter(&maps.reward); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); int radius = 10; int stepsW = w/radius; int stepsH = h/radius; //int radius = min(w,h) / steps; // we draw the rewards QColor color; fvec sample(2); FOR(i, stepsH) { float y = i/(float)stepsH*h; FOR(j, stepsW) { float x = j/(float)stepsW*w; float value = data->GetReward()->ValueAt(toSampleCoords(x,y)); if(value > 0) color = QColor(255, 255 - (int)(max(0.f,min(1.f, value)) * 255), 255 - (int)(max(0.f,min(1.f, value)) * 255)); else color = QColor(255 - (int)(max(0.f,min(1.f, -value)) * 255),255 - (int)(max(0.f,min(1.f, -value)) * 255),255); painter.setBrush(color); painter.setPen(Qt::black); painter.drawEllipse(QRectF(x-radius/2.,y-radius/2.,radius,radius)); } } } void Canvas::DrawTrajectories(QPainter &painter) { int w = width(); int h = height(); int count = data->GetCount(); bool bDrawing = false; vector sequences = data->GetSequences(); int start=0, stop=0; if(data->GetFlag(count-1) == _TRAJ) { if(sequences.size()) stop = sequences[sequences.size()-1].second; if(stop < count-1) // there's an unfinished trajectory { stop++; for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--); sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1)); bDrawing = true; } } painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); vector samples = data->GetSamples(); map counts; centers.clear(); if(trajectoryCenterType) { FOR(i, sequences.size()) { int index = sequences[i].first; if(trajectoryCenterType==1) // end { index = sequences[i].second; } int label = data->GetLabel(index); if(!centers.count(label)) { fvec center(2,0); centers[label] = center; counts[label] = 0; } centers[label] += samples[index]; counts[label]++; } for(map::iterator p = counts.begin(); p!=counts.end(); ++p) { int label = p->first; centers[label] /= p->second; } } // do the interpolation vector< vector > trajectories; vector diffs; ivec trajLabels; FOR(i, sequences.size()) { start = sequences[i].first; stop = sequences[i].second; int label = data->GetLabel(start); fvec diff(2,0); if(trajectoryCenterType && (i < sequences.size()-1 || !bDrawing)) { diff = centers[label] - samples[trajectoryCenterType==1?stop:start]; } vector trajectory(stop-start+1); int pos = 0; for (int j=start; j<=stop; j++) { trajectory[pos++] = samples[j] + diff; } switch (trajectoryResampleType) { case 0: // do nothing break; case 1: // uniform resampling { if(i < sequences.size()-1 || !bDrawing) { trajectory = interpolate(trajectory, trajectoryResampleCount); } } break; case 2: // spline resampling { if(i < sequences.size()-1 || !bDrawing) { trajectory = interpolateSpline(trajectory, trajectoryResampleCount); } } break; } trajectories.push_back(trajectory); trajLabels.push_back(data->GetLabel(start)); } // let's draw the trajectories FOR(i, trajectories.size()) { fvec oldPt = trajectories[i][0]; int count = trajectories[i].size(); int label = trajLabels[i]; FOR(j, count-1) { fvec pt = trajectories[i][j+1]; painter.setPen(QPen(Qt::black, 0.5)); painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt)); if(jGetCount(); if(!count || (!data->GetSequences().size() && (data->GetFlag(count-1) != _TRAJ))) { maps.trajectories = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.trajectories.setMask(bitmap); maps.trajectories.fill(Qt::transparent); drawnTrajectories = 0; } bool bDrawing = false; vector sequences = data->GetSequences(); int start=0, stop=0; if(data->GetFlag(count-1) == _TRAJ) { if(sequences.size()) stop = sequences.back().second; if(stop < count-1) // there's an unfinished trajectory { stop++; for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--); sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1)); bDrawing = true; } } if(!bDrawing && drawnTrajectories == sequences.size()) return; if(drawnTrajectories > sequences.size()) drawnTrajectories = 0; if(!drawnTrajectories || maps.trajectories.isNull()) { maps.trajectories = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.trajectories.setMask(bitmap); maps.trajectories.fill(Qt::transparent); drawnTrajectories = 0; } QPainter painter(&maps.trajectories); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); ivec trajLabels(sequences.size()); FOR(i, sequences.size()) { trajLabels[i] = data->GetLabel(sequences[i].first); } vector< vector > trajectories = data->GetTrajectories(trajectoryResampleType, trajectoryResampleCount, trajectoryCenterType, 0.1, true); if(bDrawing) { vector trajectory; for(int i=sequences.back().first; iGetSample(i)); } if(trajectory.size()) trajectories.push_back(trajectory); } // let's draw the trajectories for(int i=drawnTrajectories; i timeseries = data->GetTimeSeries(); if((!timeseries.size() && drawnTimeseries) || (timeseries.size() == drawnTimeseries)) return; if(drawnTimeseries > timeseries.size()) drawnTimeseries = 0; QPainter painter(&maps.timeseries); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); //qDebug() << "drawing: " << timeseries.size() << "series"; // we draw all the timeseries, each with its own color for(int i=drawnTimeseries; i < timeseries.size(); i++) { painter.setPen(QPen(SampleColor[i%(SampleColorCnt-1)+1],0.5)); TimeSerie &t = timeseries[i]; if(t.size() < 2) continue; QPointF p0,p1; float count = t.timestamps.size(); p0 = toCanvasCoords(t.timestamps[0] / count, t.data[0][yIndex-1]); FOR(j, t.size()-1) { float value = t.data[j+1][yIndex-1]; p1 = toCanvasCoords(t.timestamps[j+1] / count, value); if(t.timestamps[j] == -1 || t.timestamps[j+1] == -1) continue; painter.drawLine(p0, p1); p0 = p1; } } drawnTimeseries = timeseries.size(); } void Canvas::ResizeEvent() { if(!canvasType && (width() != parentWidget()->width() || height() != parentWidget()->height())) resize(parentWidget()->size()); bNewCrosshair = true; if(!maps.reward.isNull()) { QPixmap newReward(width(), height()); newReward = maps.reward.scaled(newReward.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } if(!canvasType) RedrawAxes(); } void Canvas::mousePressEvent( QMouseEvent *event ) { int x = event->x(); int y = event->y(); fvec sample = toSampleCoords(x,y); int label = 0; if(event->button()==Qt::LeftButton) label = 1; if(event->button()==Qt::RightButton) label = 0; if(canvasType == 0) { if(event->modifiers()==Qt::AltModifier) { mouseAnchor = event->pos(); return; } emit Drawing(sample, label); } } void Canvas::mouseReleaseEvent( QMouseEvent *event ) { int x = event->x(); int y = event->y(); fvec sample = toSampleCoords(x,y); int label = 0; if(event->button()==Qt::LeftButton) label = 1; if(event->button()==Qt::RightButton) label = 0; if(canvasType == 0) { mouseAnchor = QPoint(-1,-1); if(x > 0 && x < width() && y>0 && ymodifiers() == Qt::ShiftModifier) { zooms[xIndex] += event->delta()/1000.f; qDebug() << "zooms[" << xIndex << "]: " << zooms[xIndex]; maps.grid = QPixmap(); maps.model = QPixmap(); maps.confidence = QPixmap(); //maps.reward = QPixmap(); maps.info = QPixmap(); ResetSamples(); bNewCrosshair = true; repaint(); emit(Navigation(fVec(-1,0.001))); return; } float d = 0; if (event->delta() > 100) d = 1; if (event->delta() < 100) d = -1; if(d!=0) emit Navigation(fVec(-1,d)); } void Canvas::mouseMoveEvent( QMouseEvent *event ) { if(canvasType) return; int x = event->x(); int y = event->y(); mouse = QPoint(x,y); fvec sample = toSampleCoords(x,y); if(mouseAnchor.x() == -1) mouseAnchor = event->pos(); // we navigate in our environment if(event->modifiers() == Qt::AltModifier && event->buttons() == Qt::LeftButton) { fVec d = (fromCanvas(mouseAnchor) - fromCanvas(event->pos())); qDebug() << "mouse" << event->pos() << "anchor" << mouseAnchor << "diff:" << d.x << d.y; if(d.x == 0 && d.y == 0) return; SetCenter(center + d); mouseAnchor = event->pos(); bShowCrosshair = false; emit CanvasMoveEvent(); return; } if(event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton ) { emit Navigation(sample); repaint(); } else { int label = 0; if(event->buttons()==Qt::LeftButton) label = 1; if(event->buttons()==Qt::RightButton) label = 0; emit Drawing(sample, label); } } bool Canvas::SaveScreenshot( QString filename ) { QPixmap screenshot = GetScreenshot(); return screenshot.save(filename); } QPixmap Canvas::GetScreenshot() { QPixmap screenshot(width(), height()); QPainter painter(&screenshot); bool tmp = bShowCrosshair; bShowCrosshair = false; painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Qt::white); PaintStandard(painter); bShowCrosshair = tmp; return screenshot; } bool Canvas::DeleteData( QPointF center, float radius ) { bool anythingDeleted = false; FOR(i, data->GetCount()) { QPointF dataPoint = toCanvasCoords(data->GetSample(i)); QPointF point = this->mapToParent(QPoint(dataPoint.x(), dataPoint.y())); point -= center; if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius) { anythingDeleted = true; data->RemoveSample(i); i--; } } FOR(i, data->GetObstacles().size()) { QPointF obstaclePoint= toCanvasCoords(data->GetObstacle(i).center); QPointF point = this->mapToParent(QPoint(obstaclePoint.x(), obstaclePoint.y())); point -= center; if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius) { anythingDeleted = true; data->RemoveObstacle(i); i--; } } return anythingDeleted; } void Canvas::PaintReward(fvec sample, float radius, float shift) { int w = width(); int h = height(); if(maps.reward.isNull()) { maps.reward = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.reward.setMask(bitmap); maps.reward.fill(Qt::transparent); maps.reward.fill(Qt::white); } QPainter painter(&maps.reward); painter.setRenderHint(QPainter::Antialiasing); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); QPointF center = toCanvasCoords(sample); QRadialGradient gradient( center, radius*.75); if(shift > 0) { gradient.setColorAt(0, QColor(255,0,0,shift*255)); gradient.setColorAt(1, QColor(255,0,0,0)); } else { gradient.setColorAt(0, QColor(255,255,255,-shift*255)); gradient.setColorAt(1, QColor(255,255,255,0)); } painter.setBrush(gradient); //if(shift > 0) painter.setBrush(QColor(255,0,0,shift*255)); //else painter.setBrush(QColor(255,255,255,-shift*255)); painter.setPen(Qt::NoPen); painter.drawEllipse(toCanvasCoords(sample), radius, radius); } void Canvas::PaintGaussian(QPointF position, double variance) { int w = width(); int h = height(); if(maps.reward.isNull()) { maps.reward = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.reward.setMask(bitmap); maps.reward.fill(Qt::transparent); maps.reward.fill(Qt::white); } QImage image(w, h, QImage::Format_ARGB32); image.fill(qRgb(255,255,255)); fVec pos(position.x()/(float)w, position.y()/(float)h); fVec point; float invSigma = 1./(variance*variance); float a = invSigma*sqrtf(2*PIf); float value; float minVal = 1e30, maxVal = -1e30; qDebug() << "gaussian dropped at position " << position; FOR(i, w) { point.x = i/(float)w; FOR(j, h) { point.y = j/(float)h; value = (pos - point).lengthSquared(); value = expf(-0.5*value*invSigma); value = (1.f - value); if(value < minVal) minVal = value; if(value > maxVal) maxVal = value; int color = 255.f*value; // if(color > 255) color = 255; // if(color < -255) color = 0; //int color = min(255, max(0, (int)(255.f*(1.f - value)))); image.setPixel(i,j,qRgba(255, color, color, 255)); } } QPainter painter(&maps.reward); painter.setRenderHint(QPainter::Antialiasing); painter.setCompositionMode(QPainter::CompositionMode_Darken); painter.drawPixmap(0,0,w,h,QPixmap::fromImage(image)); } void Canvas::PaintGradient(QPointF position) { int w = width(); int h = height(); if(maps.reward.isNull()) { maps.reward = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); maps.reward.setMask(bitmap); maps.reward.fill(Qt::transparent); maps.reward.fill(Qt::white); } QPainter painter(&maps.reward); painter.setRenderHint(QPainter::Antialiasing); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); QPointF center(w/2.f, h/2.f); QPointF opposite = center - (position-center); QLinearGradient gradient(opposite, position); gradient.setColorAt(0, QColor(255,255,255,255)); gradient.setColorAt(1, QColor(255,0,0,255)); painter.setBrush(gradient); painter.setPen(Qt::NoPen); painter.drawRect(maps.reward.rect()); } mldemos-0.4.3/Core/canvas.h000066400000000000000000000156461172143270300155060ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _CANVAS_H_ #define _CANVAS_H_ #include "datasetManager.h" #include "mymaths.h" #include #include #include #include #include #include struct Pixmaps { int w, h; QPixmap confidence; QPixmap reward; QPixmap model; QPixmap info; QPixmap grid; QPixmap samples; QPixmap trajectories; QPixmap obstacles; QPixmap timeseries; void clear() { confidence = QPixmap(); reward = QPixmap(); model = QPixmap(); info = QPixmap(); grid = QPixmap(); samples = QPixmap(); trajectories = QPixmap(); obstacles = QPixmap(); timeseries = QPixmap(); } }; class Canvas : public QWidget { Q_OBJECT public: Canvas(QWidget *parent); ~Canvas(); bool DeleteData(QPointF center, float radius); static bool bCrossesAsDots; void DrawSamples(); void DrawObstacles(); void DrawTrajectories(); void DrawTimeseries(); void DrawRewards(); void DrawObstacles(QPainter &painter); void DrawTrajectories(QPainter &painter); void DrawSamples(QPainter &painter); void DrawSampleColors(QPainter &painter); void DrawTargets(QPainter &painter); void DrawLiveTrajectory(QPainter &painter); void ResetSamples(){drawnSamples = 0; drawnTrajectories = 0; drawnTimeseries = 0;} void FitToData(); void DrawAxes(QPainter &painter); void RedrawAxes(); void SetCanvasType(int); void PaintGaussian(QPointF position, double variance); void PaintReward(fvec sample, float radius, float shift); void PaintGradient(QPointF position); bool bDrawing; QPainterPath DrawObstacle(Obstacle o); fvec center; float zoom; fvec zooms; fvec mins, maxes; int xIndex, yIndex, zIndex; std::vector targets; int canvasType; std::vector sampleColors; QStringList dimNames; protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void enterEvent(QEvent *event); void focusOutEvent(QFocusEvent *event); void leaveEvent(QEvent *event); void dragEnterEvent(QDragEnterEvent *); void dropEvent(QDropEvent *); public: DatasetManager *data; Pixmaps maps; QPixmap& confidencePixmap(){return maps.confidence;} QPixmap& rewardPixmap(){return maps.reward;} QPixmap& modelPixmap(){return maps.model;} QPixmap& infoPixmap(){return maps.info;} QPixmap& gridPixmap(){return maps.grid;} QPixmap& samplesPixmap(){return maps.samples;} QPixmap& trajectoriesPixmap(){return maps.trajectories;} QPixmap& obstaclesPixmap(){return maps.obstacles;} QImage qimg; QPainterPath crosshair; bool bDisplayMap, bDisplayInfo, bDisplaySingle, bDisplaySamples; bool bDisplayTrajectories, bDisplayLearned, bDisplayGrid, bDisplayTimeSeries; bool bShowCrosshair, bNewCrosshair; int trajectoryCenterType, trajectoryResampleType, trajectoryResampleCount; QPoint mouse, mouseAnchor; fvec fromCanvas(QPointF point); fvec fromCanvas(float x, float y); QPointF toCanvasCoords(float x, float y); QPointF toCanvasCoords(fvec sample); QPointF toCanvas(fVec sample); fvec toSampleCoords(QPointF point); fvec toSampleCoords(float x, float y); fvec canvasTopLeft(); fvec canvasBottomRight(); QRectF canvasRect(); void SetZoom(float zoom); void SetZoom(fvec zooms); float GetZoom(){return zoom;} void SetCenter(fvec center); fvec GetCenter(){return center;} void SetDim(int xIndex, int yIndex, int zIndex=0); std::map centers; int drawnSamples; int drawnTrajectories; int drawnTimeseries; std::vector liveTrajectory; void PaintStandard(QPainter &painter, bool bSvg=false); void PaintMultivariate(QPainter &painter, int type); void PaintVariable(QPainter &painter, int type, fvec params); bool SaveScreenshot(QString filename); QPixmap GetScreenshot(); public slots: void ResizeEvent(); void SetConfidenceMap(QImage image); void SetModelImage(QImage image); signals: void DrawCrosshair(); void Drawing(fvec sample, int label); void CanvasMoveEvent(); void Released(); void Navigation(fvec sample); public: /* static QPixmap toPixmap(IplImage *src) { QPixmap pixmap; if(src->nChannels == 4) { pixmap = QPixmap::fromImage(QImage((const unsigned char *)src->imageData,src->width, src->height, QImage::Format_RGB32)).copy(); } else { IplImage *image = cvCreateImage(cvGetSize(src),8,4); cvCvtColor(src, image, src->nChannels==1 ? CV_GRAY2BGRA : CV_BGR2BGRA); QImage qimg = QImage((const unsigned char *)image->imageData, image->width, image->height, QImage::Format_RGB32); pixmap = QPixmap::fromImage(qimg).copy(); cvReleaseImage(&image); } return pixmap; } */ static void drawCross(QPainter &painter, QPointF point, float radius, int label) { float x = point.x(); float y = point.y(); QColor c1 = SampleColor[label%SampleColorCnt]; QColor c2 = Qt::black; if(label == 1) { c1 = Qt::black; c2 = Qt::white; } QPen pen = painter.pen(); pen.setColor(c1);pen.setWidth(3); painter.setPen(pen); painter.drawLine(QPointF(x-radius, y-radius), QPointF(x+radius, y+radius)); painter.drawLine(QPointF(x+radius, y-radius), QPointF(x-radius, y+radius)); pen.setColor(c2);pen.setWidth(1); painter.setPen(pen); painter.drawLine(QPointF(x-radius, y-radius), QPointF(x+radius, y+radius)); painter.drawLine(QPointF(x+radius, y-radius), QPointF(x-radius, y+radius)); } static void drawSample(QPainter &painter, QPointF point, float radius, int label) { float x = point.x(); float y = point.y(); QColor color = SampleColor[label%SampleColorCnt]; QColor edge = Qt::black; //if(label == 1) //{ // color = Qt::black; // edge = Qt::white; //} // radius = 10; painter.setBrush(color); painter.setPen(edge); painter.drawEllipse(QRectF(x-radius/2.,y-radius/2.,radius,radius)); } }; #endif // _CANVAS_H_ mldemos-0.4.3/Core/classifier.h000066400000000000000000000045701172143270300163510ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _CLASSIFIER_H_ #define _CLASSIFIER_H_ #include #include #include "public.h" #include "roc.h" #include "types.h" #include "mymaths.h" class Classifier { protected: std::vector< fvec > samples; ivec labels; u32 dim; u32 posClass; bool bSingleClass; bool bUsesDrawTimer; bool bMultiClass; public: std::map classMap, inverseMap; std::map classes; std::vector crossval; fvec fmeasures; std::vector< std::vector > rocdata; std::vector roclabels; Classifier(): posClass(0), bSingleClass(true), bUsesDrawTimer(true), bMultiClass(false) { rocdata.push_back(std::vector()); rocdata.push_back(std::vector()); roclabels.push_back("training"); roclabels.push_back("testing"); }; virtual ~Classifier(){} std::vector GetSamples(){return samples;} virtual void Train(std::vector< fvec > samples, ivec labels){} virtual fvec TestMulti(const fvec &sample){ return fvec(1,Test(sample));} virtual float Test(const fvec &sample){ return 0; } virtual float Test(const fVec &sample){ if(dim==2) return Test((fvec)sample); fvec s = (fvec)sample; s.resize(dim,0); return Test(s);} virtual char *GetInfoString(){return NULL;} bool SingleClass(){return bSingleClass;} bool UsesDrawTimer(){return bUsesDrawTimer;} bool IsMultiClass(){return bMultiClass;} int Dim(){return dim;} }; #endif // _CLASSIFIER_H_ mldemos-0.4.3/Core/clusterer.h000066400000000000000000000032441172143270300162320ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _CLUSTERING_H_ #define _CLUSTERING_H_ #include #include "mymaths.h" class Clusterer { protected: u32 dim; u32 nbClusters; bool bIterative; public: Clusterer() : dim(2), bIterative(false), nbClusters(1) {} ~Clusterer(){} void Cluster(std::vector< fvec > allsamples) {Train(allsamples);} void SetIterative(bool iterative){bIterative = iterative;} int NbClusters(){return nbClusters;} virtual void Train(std::vector< fvec > samples){} virtual fvec Test( const fvec &sample){ return fvec(); } virtual fvec Test(const fVec &sample){ return Test((fvec)sample); } virtual char *GetInfoString(){ return NULL; } virtual void SetNbClusters(int count){ nbClusters = count; } }; #endif // _CLUSTERING_H_ mldemos-0.4.3/Core/dataImport.ui000066400000000000000000000125111172143270300165110ustar00rootroot00000000000000 DataImporterDialog 0 0 757 588 0 0 300 300 16777215 16777215 Projections 130 0 0 0 9 Load Dataset File true 10 First Row as Header 10 Class Column: Send Data 8 0 0 Qt::Vertical 20 40 9 Close 10 Ignore Class (set to 0) 0 Dataset 0 0 QAbstractItemView::NoEditTriggers QAbstractItemView::SelectColumns Ctrl + Click to select multiple columns. Selected columns will be excluded from the input mldemos-0.4.3/Core/dataImporter.cpp000066400000000000000000000141001172143270300172010ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2011 Chrstophe Paccolat Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "dataImporter.h" #include "ui_dataImport.h" DataImporter::DataImporter() : guiDialog(0), gui(0), inputParser(0) { } DataImporter::~DataImporter() { if(gui && guiDialog) guiDialog->hide(); DEL(inputParser); } void DataImporter::Start() { if(!gui) { gui = new Ui::DataImporterDialog(); gui->setupUi(guiDialog = new QDialog()); guiDialog->setWindowTitle("CVS Import"); connect(gui->closeButton, SIGNAL(clicked()), this, SLOT(Closing())); connect(guiDialog, SIGNAL(finished(int)), this, SLOT(Closing())); connect(gui->classColumnSpin, SIGNAL(valueChanged(int)), this, SLOT(classColumnChanged(int))); connect(gui->headerCheck, SIGNAL(clicked()), this, SLOT(headerChanged())); connect(gui->loadFile, SIGNAL(clicked()), this, SLOT(LoadFile())); // file loader connect(gui->dumpButton, SIGNAL(clicked()),this,SLOT(SendData())); connect(gui->classIgnoreCheck, SIGNAL(clicked()), this, SLOT(classIgnoreChanged())); guiDialog->show(); } else guiDialog->show(); if(!inputParser) inputParser = new CSVParser(); } void DataImporter::Stop() { guiDialog->hide(); } void DataImporter::Closing() { guiDialog->hide(); emit(Done(this)); } bool DataImporter::saveFile(const QString &filename, QIODevice *data) { QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "Could not open " << qPrintable(filename) << " for writing: " << qPrintable(file.errorString()); return false; } file.write(data->readAll()); file.close(); return true; } void DataImporter::LoadFile() { QString filename = QFileDialog::getOpenFileName(NULL, tr("Load Data"), QDir::currentPath(), tr("dataset files (*.data *.csv);;All files (*.*)")); if(filename.isEmpty()) return; Parse(filename); } void DataImporter::Parse(QString filename) { if(filename.isEmpty()) return; headers.clear(); inputParser->clear(); inputParser->parse(filename.toStdString().c_str()); vector > rawData = inputParser->getRawData(); if(rawData.size() < 2) return; bool bUseHeader = gui->headerCheck->isChecked(); gui->tableWidget->clear(); gui->tableWidget->setRowCount(rawData.size()); gui->tableWidget->setColumnCount(rawData[0].size()); if(bUseHeader) { QStringList headerLabels; FOR(i, rawData[0].size()) { headers << rawData[0][i].c_str(); headerLabels << QString("%1:").arg(i+1) + rawData[0][i].c_str(); } gui->tableWidget->setHorizontalHeaderLabels(headerLabels); } for(size_t r = 0; r < rawData.size(); r++) { if(!r && bUseHeader) continue; for(size_t c = 0; c < rawData[r].size(); c++) { QTableWidgetItem *newItem = new QTableWidgetItem(QString(rawData[r][c].c_str())); gui->tableWidget->setItem(r-bUseHeader, c, newItem); } } gui->classColumnSpin->setRange(1,rawData[0].size()); } void DataImporter::FetchResults(std::vector results) { } void DataImporter::classIgnoreChanged() { classColumnChanged(0); } void DataImporter::headerChanged() { headers.clear(); vector > rawData = inputParser->getRawData(); if(rawData.size() < 2) return; bool bUseHeader = gui->headerCheck->isChecked(); gui->tableWidget->clear(); gui->tableWidget->setRowCount(rawData.size()); gui->tableWidget->setColumnCount(rawData[0].size()); if(bUseHeader) { QStringList headerLabels; FOR(i, rawData[0].size()) { headers << rawData[0][i].c_str(); headerLabels << QString("%1:").arg(i+1) + rawData[0][i].c_str(); } gui->tableWidget->setHorizontalHeaderLabels(headerLabels); } for(size_t r = 0; r < rawData.size(); r++) { if(!r && bUseHeader) continue; for(size_t c = 0; c < rawData[r].size(); c++) { QTableWidgetItem *newItem = new QTableWidgetItem(QString(rawData[r][c].c_str())); gui->tableWidget->setItem(r-bUseHeader, c, newItem); } } gui->classColumnSpin->setRange(1,rawData[0].size()); } void DataImporter::classColumnChanged(int value) { if(gui->classIgnoreCheck->isChecked()) { inputParser->setOutputColumn(-1); } else inputParser->setOutputColumn(value-1); } void DataImporter::SendData() { ivec excludeIndices; vector bExcluded(gui->tableWidget->columnCount(), false); QModelIndexList indexes = gui->tableWidget->selectionModel()->selection().indexes(); FOR(i, indexes.count()) { QModelIndex index = indexes.at(i); bExcluded[index.column()] = true; } FOR(i, bExcluded.size()) { if(bExcluded[i]) excludeIndices.push_back(i); } inputParser->setFirstRowAsHeader(gui->headerCheck->isChecked()); pair,ivec> data = inputParser->getData(excludeIndices, 1000); emit(SetData(data.first, data.second, vector(), false)); emit(SetDimensionNames(headers)); } mldemos-0.4.3/Core/dataImporter.h000066400000000000000000000043421172143270300166550ustar00rootroot00000000000000#ifndef _DATA_IMPORTER_H_ #define _DATA_IMPORTER_H_ #include "parser.h" #include #include #include #include namespace Ui { class DataImporterDialog; } class DataImporter : public QObject, public InputOutputInterface { Q_OBJECT Q_INTERFACES(InputOutputInterface) public: const char* QueryClassifierSignal() {return SIGNAL(QueryClassifier(std::vector));} const char* QueryRegressorSignal() {return SIGNAL(QueryRegressor(std::vector));} const char* QueryDynamicalSignal() {return SIGNAL(QueryDynamical(std::vector));} const char* QueryClustererSignal() {return SIGNAL(QueryClusterer(std::vector));} const char* QueryMaximizerSignal() {return SIGNAL(QueryMaximizer(std::vector));} const char* SetDataSignal() {return SIGNAL(SetData(std::vector, ivec, std::vector, bool));} const char* SetTimeseriesSignal() {return SIGNAL(SetTimeseries(std::vector));} const char* FetchResultsSlot() {return SLOT(FetchResults(std::vector));} const char* DoneSignal() {return SIGNAL(Done(QObject *));} QObject *object(){return this;} QString GetName(){return "DataImporter";} void Start(); void Stop(); QStringList GetHeaders(){return headers;} DataImporter(); ~DataImporter(); private: Ui::DataImporterDialog *gui; QDialog *guiDialog; CSVParser *inputParser; QStringList headers; bool saveFile(const QString &filename, QIODevice *data); signals: void Done(QObject *); void SetData(std::vector samples, ivec labels, std::vector trajectories, bool bProjected); void SetTimeseries(std::vector series); void SetDimensionNames(QStringList headers); void QueryClassifier(std::vector samples); void QueryRegressor(std::vector samples); void QueryDynamical(std::vector samples); void QueryClusterer(std::vector samples); void QueryMaximizer(std::vector samples); public slots: void FetchResults(std::vector results); void Closing(); void Parse(QString filename); void LoadFile(); void SendData(); private slots: void classIgnoreChanged(); void headerChanged(); void classColumnChanged(int value); }; #endif // _DATA_IMPORTER_H_ mldemos-0.4.3/Core/datasetManager.cpp000066400000000000000000000473271172143270300175070ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "public.h" #include "basicMath.h" #include "mymaths.h" #include "datasetManager.h" #include #include #include using namespace std; /******************************************/ /* */ /* DATASET MANAGER */ /* */ /******************************************/ u32 DatasetManager::IDCount = 0; DatasetManager::DatasetManager(int dimension) : size(dimension) { bProjected = false; ID = IDCount++; perm = NULL; } DatasetManager::~DatasetManager() { Clear(); } void DatasetManager::Clear() { bProjected = false; samples.clear(); obstacles.clear(); flags.clear(); labels.clear(); sequences.clear(); rewards.Clear(); KILL(perm); } void DatasetManager::AddSample(fvec sample, int label, dsmFlags flag) { if (!sample.size()) return; size = sample.size(); samples.push_back(sample); labels.push_back(label); flags.push_back(flag); KILL(perm); perm = randPerm(samples.size()); } void DatasetManager::AddSamples(std::vector< fvec > newSamples, ivec newLabels, std::vector newFlags) { FOR(i, newSamples.size()) { if(newSamples[0].size()) size = newSamples[0].size(); if(newSamples[i].size()) { samples.push_back(newSamples[i]); if(i < newFlags.size()) flags.push_back(newFlags[i]); else flags.push_back(_UNUSED); } } if(newLabels.size() == newSamples.size()) FOR(i, newLabels.size()) labels.push_back(newLabels[i]); else FOR(i, newSamples.size()) labels.push_back(0); KILL(perm); perm = randPerm(samples.size()); } void DatasetManager::AddSamples(DatasetManager &newSamples) { AddSamples(newSamples.GetSamples(), newSamples.GetLabels(), newSamples.GetFlags()); } void DatasetManager::RemoveSample(unsigned int index) { if(index >= samples.size()) return; if(samples.size() == 1) { Clear(); return; } samples[index].clear(); for (unsigned int i = index; i < samples.size()-1; i++) { samples[i] = samples[i+1]; labels[i] = labels[i+1]; flags[i] = flags[i+1]; } samples.pop_back(); labels.pop_back(); flags.pop_back(); // we need to check if a sequence needs to be shortened FOR(i, sequences.size()) { if(sequences[i].first > index) // later sequences { sequences[i].first--; sequences[i].second--; } else if(sequences[i].first == index || sequences[i].second >= index) { sequences[i].second--; } if(sequences[i].first >= sequences[i].second) // we need to pop out the sequence { if(sequences[i].first == sequences[i].second) { flags[sequences[i].first] = _UNUSED; } for(int j=i; j samples.size()) return; // we sort the indices sort(indices.begin(), indices.end(), less()); int offset = 0; FOR(i, indices.size()) { int index = indices[i] - offset; if(index < 0 || index > samples.size()) continue; RemoveSample(index); offset++; } } void DatasetManager::AddSequence(int start, int stop) { if(start >= samples.size() || stop >= samples.size()) return; for(int i=start; i<=stop; i++) flags[i] = _TRAJ; sequences.push_back(ipair(start,stop)); // sort sequences by starting value std::sort(sequences.begin(), sequences.end()); } void DatasetManager::AddSequence(ipair newSequence) { if(newSequence.first >= samples.size() || newSequence.second >= samples.size()) return; for(int i=newSequence.first; i<=newSequence.second; i++) flags[i] = _TRAJ; sequences.push_back(newSequence); // sort sequences by starting value std::sort(sequences.begin(), sequences.end()); } void DatasetManager::AddSequences(std::vector< ipair > newSequences) { sequences.reserve(sequences.size()+newSequences.size()); FOR(i, newSequences.size()) { sequences.push_back(newSequences[i]); } } void DatasetManager::RemoveSequence(unsigned int index) { if(index >= sequences.size()) return; for(int i=index; i data, std::vector timestamps) { TimeSerie serie; serie.name = name; serie.data = data; serie.timestamps = timestamps; AddTimeSerie(serie); } void DatasetManager::AddTimeSerie(TimeSerie serie) { series.push_back(serie); } void DatasetManager::AddTimeSeries(std::vector< TimeSerie > newTimeSeries) { series.insert(series.end(), newTimeSeries.begin(), newTimeSeries.end()); } void DatasetManager::RemoveTimeSerie(unsigned int index) { if(index >= series.size()) return; series.erase(series.begin() + index); } void DatasetManager::AddObstacle(fvec center, fvec axes, float angle, fvec power, fvec repulsion) { Obstacle o; o.center = center; o.axes = axes; o.angle = angle; o.power = power; o.repulsion = repulsion; obstacles.push_back(o); } void DatasetManager::AddObstacles(std::vector newObstacles) { FOR(i, newObstacles.size()) obstacles.push_back(newObstacles[i]); } void DatasetManager::RemoveObstacle(unsigned int index) { if(index >= obstacles.size()) return; for(int i=index; i dist) { index = i; minDist = dist; } } return minDist; } void DatasetManager::Randomize(int seed) { KILL(perm); if(samples.size()) perm = randPerm(samples.size(), seed); } void DatasetManager::ResetFlags() { FOR(i, samples.size()) flags[i] = _UNUSED; } void DatasetManager::SetSample(int index, fvec sample) { if(index >= 0 && index < samples.size()) samples[index] = sample; } fvec DatasetManager::GetSampleDim(int index, ivec inputDims, int outputDim) { if(index>=samples.size()) return fvec(); if(!inputDims.size()) return samples[index]; int dim = inputDims.size(); fvec sample(dim + outputDim!=-1?1:0); FOR(d, dim) sample[d] = samples[index][inputDims[d]]; if(outputDim != -1) sample[dim] = samples[index][outputDim]; return sample; } std::vector< fvec > DatasetManager::GetSampleDims(ivec inputDims, int outputDim) { if(!inputDims.size()) return samples; vector newSamples = samples; int newDim = inputDims.size() + (outputDim != -1 ? 1 : 0); FOR(i, samples.size()) { fvec newSample(newDim); FOR(d, inputDims.size()) { newSample[d] = samples[i][inputDims[d]]; } if(outputDim != -1) newSample[newDim-1] = samples[i][outputDim]; newSamples[i] = newSample; } return newSamples; } std::vector< fvec > DatasetManager::GetSamples(u32 count, dsmFlags flag, dsmFlags replaceWith) { std::vector< fvec > selected; if (!samples.size() || !perm) return selected; if (!count) { FOR(i, samples.size()) { if ( flags[perm[i]] == flag) { selected.push_back(samples[perm[i]]); flags[perm[i]] = replaceWith; } } return selected; } for ( u32 i=0, cnt=0; i < samples.size() && cnt < count; i++ ) { if ( flags[perm[i]] == flag ) { selected.push_back(samples[perm[i]]); flags[perm[i]] = replaceWith; cnt++; } } return selected; } std::vector< std::vector < fvec > > DatasetManager::GetTrajectories(int resampleType, int resampleCount, int centerType, float dT, int zeroEnding) { // we split the data into trajectories vector< vector > trajectories; if(!sequences.size() || !samples.size()) return trajectories; int dim = samples[0].size(); trajectories.resize(sequences.size()); FOR(i, sequences.size()) { int length = sequences[i].second-sequences[i].first+1; trajectories[i].resize(length); FOR(j, length) { trajectories[i][j].resize(dim*2); // copy data FOR(d, dim) trajectories[i][j][d] = samples[sequences[i].first + j][d]; } } switch(resampleType) { case 0: // none { FOR(i,sequences.size()) { int cnt = sequences[i].second-sequences[i].first+1; if(resampleCount > cnt) resampleCount = cnt; } FOR(i, trajectories.size()) { while(trajectories[i].size() > resampleCount) trajectories[i].pop_back(); } } break; case 1: // uniform { FOR(i, trajectories.size()) { vector trajectory = trajectories[i]; trajectories[i] = interpolate(trajectory, resampleCount); } } break; case 2: // spline { FOR(i, trajectories.size()) { vector trajectory = trajectories[i]; trajectories[i] = interpolateSpline(trajectory, resampleCount); } } break; } if(centerType) { map counts; map centers; vector trajLabels(sequences.size()); FOR(i, sequences.size()) { int index = centerType==1 ? sequences[i].second : sequences[i].first; // start int label = GetLabel(index); trajLabels[i] = label; if(!centers.count(label)) { fvec center(dim,0); centers[label] = center; counts[label] = 0; } centers[label] += samples[index]; counts[label]++; } for(map::iterator p = counts.begin(); p!=counts.end(); ++p) { int label = p->first; centers[label] /= p->second; } FOR(i, trajectories.size()) { if(centerType == 1) { fvec difference = centers[trajLabels[i]] - trajectories[i].back(); FOR(j, resampleCount) trajectories[i][j] += difference; } else { fvec difference = centers[trajLabels[i]] - trajectories[i][0]; FOR(j, resampleCount) trajectories[i][j] += difference; } } } float maxV = -FLT_MAX; // we compute the velocity FOR(i, trajectories.size()) { FOR(j, resampleCount-1) { FOR(d, dim) { float velocity = (trajectories[i][j+1][d] - trajectories[i][j][d]) / dT; trajectories[i][j][dim + d] = velocity; if(velocity > maxV) maxV = velocity; } } if(!zeroEnding) { FOR(d, dim) { trajectories[i][resampleCount-1][dim + d] = trajectories[i][resampleCount-2][dim + d]; } } } // we normalize the velocities as the variance of the data fvec mean, sigma; mean.resize(dim,0); int cnt = 0; sigma.resize(dim,0); FOR(i, trajectories.size()) { FOR(j, resampleCount) { mean += trajectories[i][j]; cnt++; } } mean /= cnt; FOR(i, trajectories.size()) { FOR(j, resampleCount) { fvec diff = (mean - trajectories[i][j]); FOR(d,dim) sigma[d] += diff[d]*diff[d]; } } sigma /= cnt; FOR(i, trajectories.size()) { FOR(j, resampleCount) { FOR(d, dim) { trajectories[i][j][dim + d] /= maxV; //trajectories[i][j][dim + d] /= sqrt(sigma[d]); } } } return trajectories; } void DatasetManager::Save(const char *filename) { if(!samples.size()) return; u32 sampleCnt = samples.size(); ofstream file(filename); if(!file.is_open()) return; file << sampleCnt << " " << size << "\n"; FOR(i, sampleCnt) { FOR(j,size) { file << samples[i][j] << " "; } file << labels[i] << " "; file << flags[i] << " "; file << "\n"; } if(sequences.size()) { file << "s " << sequences.size() << "\n"; FOR(i, sequences.size()) { file << sequences[i].first << " " << sequences[i].second << "\n"; } } // we load the obstacles if(obstacles.size()) { file << "o " << obstacles.size() << "\n"; FOR(i, obstacles.size()) { FOR(j, size) file << obstacles[i].center[j] << " "; FOR(j, size) file << obstacles[i].axes[j] << " "; file << obstacles[i].angle << " "; file << obstacles[i].power[0] << " "; file << obstacles[i].power[1] << " "; file << obstacles[i].repulsion[0] << " "; file << obstacles[i].repulsion[1] << "\n"; } } file.close(); } bool DatasetManager::Load(const char *filename) { ifstream file(filename); if(!file.is_open()) return false; Clear(); int sampleCnt; file >> sampleCnt; file >> size; // we load the samples FOR(i, sampleCnt) { fvec sample; sample.resize(size,0); int label, flag; FOR(j, size) { file >> sample[j]; } file >> label; file >> flag; samples.push_back(sample); labels.push_back(label); flags.push_back((dsmFlags)flag); } // we load the sequences char tmp[255]; file.getline(tmp,255); // we skip the rest of the line int nextChar = file.peek(); if(nextChar == 's') // we have sequences! { char dump; file >> dump; int sequenceCount; file >> sequenceCount; FOR(i, sequenceCount) { int start, stop; file >> start; file >> stop; sequences.push_back(ipair(start,stop)); } file.getline(tmp,255); nextChar = file.peek(); } // we load the obstacles if(nextChar == 'o') { char dump; file >> dump; int obstacleCount; file >> obstacleCount; Obstacle obstacle; obstacle.center.resize(size); obstacle.axes.resize(size); obstacle.power.resize(size); obstacle.repulsion.resize(size); FOR(i, obstacleCount) { FOR(j, size) file >> obstacle.center[j]; FOR(j, size) file >> obstacle.axes[j]; file >> obstacle.angle; FOR(j, size) file >> obstacle.power[j]; FOR(j, size) file >> obstacle.repulsion[j]; obstacles.push_back(obstacle); } } file.close(); KILL(perm); perm = randPerm(samples.size()); return samples.size() > 0; } int DatasetManager::GetDimCount() { int dim = 2; if(samples.size()) dim = samples[0].size(); if(series.size() && series[0].size()) { dim = series[0][0].size()+1; } return dim; } std::pair DatasetManager::GetBounds() { if(!samples.size()) return make_pair(fvec(),fvec()); int dim = samples[0].size(); fvec mins(dim,FLT_MAX), maxes(dim,-FLT_MAX); FOR(i, samples.size()) { fvec& sample = samples[i]; int dim = sample.size(); FOR(d,dim) { if(mins[d] > sample[d]) mins[d] = sample[d]; if(maxes[d] < sample[d]) maxes[d] = sample[d]; } } return make_pair(mins, maxes); } u32 DatasetManager::GetClassCount(ivec classes) { u32 counts[256]; memset(counts, 0, 256*sizeof(u32)); FOR(i, classes.size()) counts[classes[i]]++; u32 result = 0; for (u32 i=1; i<256; i++) result += counts[i] > 0 ? 1 : 0; return result; } bvec DatasetManager::GetFreeFlags() { bvec res; FOR(i, flags.size()) res.push_back(flags[i] == _UNUSED); return res; } /******************************************/ /* */ /* REWARD MAPS */ /* */ /******************************************/ RewardMap& RewardMap::operator= (const RewardMap& r) { if (this != &r) { dim = r.dim; size = r.size; length = r.length; lowerBoundary = r.lowerBoundary; higherBoundary = r.higherBoundary; if(rewards) delete [] rewards; rewards = new float[length]; memcpy(rewards, r.rewards, length*sizeof(float)); } return *this; } void RewardMap::SetReward(float *rewards, ivec size, fvec lowerBoundary, fvec higherBoundary) { this->lowerBoundary = lowerBoundary; this->higherBoundary = higherBoundary; this->size = size; dim = size.size(); length = 1; FOR(i, size.size()) length *= size[i]; if(this->rewards) delete [] this->rewards; this->rewards = new float[length]; memcpy(this->rewards, rewards, length*sizeof(float)); } void RewardMap::Clear() { dim = 0; size.clear(); length = 0; lowerBoundary.clear(); higherBoundary.clear(); if(rewards) delete [] rewards; } void RewardMap::Zero() { FOR(i, length) rewards[i] = 0; } // return the value of the reward function at the coordinates provided float RewardMap::ValueAt(fvec sample) { if(!rewards) return 0.f; ivec index; index.resize(dim); FOR(d, dim) { //we check if we're outside the boundaries if(sample[d] < lowerBoundary[d]) sample[d] = lowerBoundary[d]; if(sample[d] > higherBoundary[d]) sample[d] = higherBoundary[d]; // now we get the closest index on the map index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]); } // we convert the map index to a vector index int rewardIndex = 0; FOR(d,dim) { rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1]; } //printf("sample: %f %f index: %d %d (%d) value: %f\n", sample[0], sample[1], index[0], index[1], rewardIndex, rewards[rewardIndex]); // TODO: return interpolation of closest indices instead of the closest index itself return rewards[rewardIndex]; } void RewardMap::SetValueAt(fvec sample, float value) { if(!rewards) return; ivec index; index.resize(dim); FOR(d, dim) { //we check if we're outside the boundaries if(sample[d] < lowerBoundary[d]) return; if(sample[d] > higherBoundary[d]) return; // now we get the closest index on the map index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]); } // we convert the map index to a vector index int rewardIndex = 0; FOR(d,dim) { rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1]; } rewards[rewardIndex] = value; } void RewardMap::ShiftValueAt(fvec sample, float shift) { if(!rewards) return; ivec index; index.resize(dim); FOR(d, dim) { //we check if we're outside the boundaries if(sample[d] < lowerBoundary[d]) return; if(sample[d] > higherBoundary[d]) return; // now we get the closest index on the map index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]); } // we convert the map index to a vector index int rewardIndex = 0; FOR(d,dim) { rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1]; } printf("index: %d value: %f\n", rewardIndex, rewards[rewardIndex]); rewards[rewardIndex] += shift; } void RewardMap::ShiftValueAt(fvec sample, float radius, float shift) { if(!rewards) return; ivec index; index.resize(dim); ivec lowIndex = index, hiIndex = index; ivec steps; steps.resize(dim); FOR(d, dim) { //we check if we're outside the boundaries if(sample[d] < lowerBoundary[d]) return; if(sample[d] > higherBoundary[d]) return; // now we get the closest index on the map steps[d] = (int)(2*radius / (higherBoundary[d] - lowerBoundary[d]) * size[d]); index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]); lowIndex[d] = (int)((sample[d] - radius - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]); } FOR(i, steps[1]) { FOR(j, steps[0]) { float x = 2.f*(j - steps[0]*0.5f)/float(steps[0]); float y = 2.f*(i - steps[1]*0.5f)/float(steps[0]); if(x*x + y*y > 1) continue; // we convert the map index to a vector index int rewardIndex = index[0] - steps[0]/2 + j + (index[1] - steps[1]/2 + i)*size[0]; if(rewardIndex < 0 || rewardIndex>=length) return; rewards[rewardIndex] += shift; } } } mldemos-0.4.3/Core/datasetManager.h000066400000000000000000000202741172143270300171440ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _DATASET_MANAGER_H_ #define _DATASET_MANAGER_H_ #include #include "public.h" enum DatasetManagerFlags { _UNUSED = 0x0000, _TRAIN = 0x0001, _VALID = 0x0010, _TEST = 0x0100, _TRAJ = 0x1000, _OBST = 0x10000, _TIME = 0x100000 }; typedef DatasetManagerFlags dsmFlags; struct Obstacle { fvec axes; //the obstacle major axes fvec center; //the center of the obstacle float angle; //the orientation matrix fvec power; //Gamma is \sum( (x/a)^m ) fvec repulsion; //safety factor Obstacle() :angle(0) { axes.resize(2,1.f); center.resize(2,0.f); power.resize(2,1.f); repulsion.resize(2,1.f); }; bool operator==(const Obstacle& o) const { return center == o.center && axes == o.axes && angle == o.angle && power == o.power && repulsion == o.repulsion; } bool operator!=(const Obstacle& o) const { return center != o.center || axes != o.axes || angle != o.angle || power != o.power || repulsion != o.repulsion; } }; struct RewardMap { int dim; ivec size; // size of reward array in each dimension int length; // size[0]*size[1]*...*size[dim] float *rewards; fvec lowerBoundary; fvec higherBoundary; RewardMap():rewards(0), dim(0), length(0){} ~RewardMap(){if(rewards) delete [] rewards;} RewardMap& operator= (const RewardMap& r); void SetReward(float *rewards, ivec size, fvec lowerBoundary, fvec higherBoundary); void Clear(); void Zero(); // return the value of the reward function at the coordinates provided float ValueAt(fvec sample); void SetValueAt(fvec sample, float value); void ShiftValueAt(fvec sample, float shift); void ShiftValueAt(fvec sample, float radius, float shift); }; struct TimeSerie { std::string name; // name of the current graph line std::vector timestamps; // time stamps for each frame std::vector data; // each vector element is a frame TimeSerie(std::string name="", std::vector timestamps=std::vector(), std::vector data=std::vector()) : name(name), timestamps(timestamps), data(data){}; bool operator==(const TimeSerie& t) const { if(name != t.name || timestamps.size() != t.timestamps.size() || data.size() != t.data.size()) return false; for(int i=0; i::iterator begin(){return data.begin();} std::vector::iterator end(){return data.end();} TimeSerie& operator+=(const TimeSerie& t) { data.insert(data.end(), t.data.begin(), t.data.end()); int count = timestamps.size(); int lastTimestamp = timestamps.back(); timestamps.insert(timestamps.end(), t.timestamps.begin(), t.timestamps.end()); for(int i=count; i < timestamps.size(); i++) timestamps[i] += lastTimestamp; return *this;} TimeSerie operator+(const TimeSerie& t) const {TimeSerie a = *this; a+=t; return a;} TimeSerie& operator<< (const TimeSerie& t) {return *this += t;}; TimeSerie& operator+=(const fvec& v) {data.push_back(v); timestamps.push_back(timestamps.back()+1); return *this;} TimeSerie operator+(const fvec& v) const {TimeSerie a = *this; a+=v; return a;} TimeSerie& operator<< (const fvec& v) {return *this += v;}; }; class DatasetManager { protected: static u32 IDCount; u32 ID; int size; // the samples size (dimension) std::vector< fvec > samples; std::vector< ipair > sequences; std::vector flags; std::vector obstacles; std::vector series; RewardMap rewards; ivec labels; u32 *perm; public: bool bProjected; public: DatasetManager(int dimension = 2); ~DatasetManager(); void Randomize(int seed=-1); void Clear(); double Compare(fvec sample); int GetSize(){return size;} int GetCount(){return samples.size();} int GetDimCount(); std::pair GetBounds(); static u32 GetClassCount(ivec classes); // functions to manage samples void AddSample(fvec sample, int label = 0, dsmFlags flag = _UNUSED); void AddSamples(std::vector< fvec > samples, ivec newLabels=ivec(), std::vector newFlags=std::vector()); void AddSamples(DatasetManager &newSamples); void RemoveSample(unsigned int index); void RemoveSamples(ivec indices); fvec GetSample(int index=0){ return (index < samples.size()) ? samples[index] : fvec(); } fvec GetSampleDim(int index, ivec inputDims, int outputDim=-1); std::vector< fvec > GetSamples(){return samples;} std::vector< fvec > GetSamples(u32 count, dsmFlags flag=_UNUSED, dsmFlags replaceWith=_TRAIN); std::vector< fvec > GetSampleDims(ivec inputDims, int outputDim=-1); void SetSample(int index, fvec sample); void SetSamples(std::vector samples){this->samples = samples;} int GetLabel(int index){return index < labels.size() ? labels[index] : 0;} ivec GetLabels(){return labels;} void SetLabel(int index, int label){if(indexlabels = labels;} // functions to manage sequences void AddSequence(int start, int stop); void AddSequence(ipair newSequence); void AddSequences(std::vector< ipair > newSequences); void RemoveSequence(unsigned int index); ipair GetSequence(unsigned int index){return index < sequences.size() ? sequences[index] : ipair(-1,-1);} std::vector< ipair > GetSequences(){return sequences;} std::vector< std::vector > GetTrajectories(int resampleType, int resampleCount, int centerType, float dT, int zeroEnding); // functions to manage obstacles void AddObstacle(Obstacle o){obstacles.push_back(o);} void AddObstacle(fvec center, fvec axes, float angle, fvec power, fvec repulsion); void AddObstacles(std::vector newObstacles); void RemoveObstacle(unsigned int index); std::vector< Obstacle > GetObstacles(){return obstacles;} Obstacle GetObstacle(unsigned int index){return index < obstacles.size() ? obstacles[index] : Obstacle();} // functions to manage rewards void AddReward(float *values, ivec size, fvec lowerBoundary, fvec higherBoundary); RewardMap *GetReward(){return &rewards;} // functions to manage time series void AddTimeSerie(std::string name, std::vector data, std::vector timestamps=std::vector()); void AddTimeSerie(TimeSerie serie); void AddTimeSeries(std::vector< TimeSerie > newTimeSeries); void RemoveTimeSerie(unsigned int index); std::vector& GetTimeSeries(){return series;} // functions to manage flags dsmFlags GetFlag(int index){return index < flags.size() ? flags[index] : _UNUSED;} void SetFlag(int index, dsmFlags flag){if(index < flags.size()) flags[index] = flag;} std::vector GetFlags(){return flags;} std::vector GetFreeFlags(); void ResetFlags(); void Save(const char *filename); bool Load(const char *filename); }; #endif // _DATASET_MANAGER_H_ mldemos-0.4.3/Core/drawSVG.cpp000066400000000000000000000135161172143270300160750ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include #include #include #include #include #include #include #include "public.h" #include "basicMath.h" #include "drawSVG.h" using namespace std; DrawSVG::DrawSVG(Canvas *canvas, QMutex *mutex) : canvas(canvas), classifier(0), regressor(0), dynamical(0), clusterer(0), drawClass(0), drawRegr(0), drawDyn(0), drawClust(0), drawProj(0), mutex(mutex), perm(0), w(0), h(0) { } DrawSVG::~DrawSVG() { } void DrawSVG::Write(QString filename) { if(!canvas) return; QSvgGenerator generator; generator.setFileName(filename); generator.setSize(QSize(canvas->width(), canvas->height())); generator.setTitle("MLDemos screenshot"); generator.setDescription("Generated with MLDemos"); QPainter painter; painter.begin(&generator); // we need to paint the different layers: // confidence map // samples + trajectories + reward canvas->PaintStandard(painter, true); if(canvas->bDisplayLearned) { // learned model if(classifier) drawClass->DrawModel(canvas, painter, classifier); if(regressor) drawRegr->DrawModel(canvas, painter, regressor); if(dynamical) drawDyn->DrawModel(canvas, painter, dynamical); if(clusterer) drawClust->DrawModel(canvas, painter, clusterer); if(projector) drawProj->DrawModel(canvas, painter, projector); if(dynamical) { int cnt = 10000; // not too many or it will make unreadable files int steps = 8; VectorsFast(cnt, steps, painter); } if(maximizer) { Maximization(painter); } } if(canvas->bDisplayInfo) { // model info if(classifier) drawClass->DrawInfo(canvas, painter, classifier); if(regressor) drawRegr->DrawInfo(canvas, painter, regressor); if(dynamical) drawDyn->DrawInfo(canvas, painter, dynamical); if(clusterer) drawClust->DrawInfo(canvas, painter, clusterer); if(projector) drawProj->DrawInfo(canvas, painter, projector); } painter.end(); } void DrawSVG::Vectors(int count, int steps, QPainter &painter) { if(!dynamical) return; float dT = dynamical->dT;// * (dynamical->count/100.f); //float dT = 0.02f; fvec sample; sample.resize(2,0); int w = canvas->width(); int h = canvas->height(); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); vector obstacles = canvas->data->GetObstacles(); QPointF oldPoint(-FLT_MAX,-FLT_MAX); QPointF oldPointUp(-FLT_MAX,-FLT_MAX); QPointF oldPointDown(-FLT_MAX,-FLT_MAX); FOR(i, count) { QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h); sample = canvas->toSampleCoords(samplePre); float color = (rand()/(float)RAND_MAX*0.7f)*255.f; color = 0; QPointF oldPoint = canvas->toCanvasCoords(sample); FOR(j, steps) { fvec res = dynamical->Test(sample); if(dynamical->avoid) { dynamical->avoid->SetObstacles(obstacles); fvec newRes = dynamical->avoid->Avoid(sample, res); res = newRes; } sample += res*dT; float speed = sqrtf(res[0]*res[0] + res[1]*res[1]); QPointF point = canvas->toCanvasCoords(sample); painter.setOpacity(speed); QColor c(color,color,color); painter.setPen(QPen(c, 0.25)); painter.drawLine(point, oldPoint); oldPoint = point; } } } void DrawSVG::Maximization(QPainter &painter) { if(!maximizer) return; painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); maximizer->Draw(painter); } void DrawSVG::VectorsFast(int count, int steps, QPainter &painter) { if(!dynamical) return; QPointF oldPoint(-FLT_MAX,-FLT_MAX); QPointF oldPointUp(-FLT_MAX,-FLT_MAX); QPointF oldPointDown(-FLT_MAX,-FLT_MAX); float dT = dynamical->dT;// * (dynamical->count/100.f); //float dT = 0.02f; fvec sample; sample.resize(2,0); int w = canvas->width(); int h = canvas->height(); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); vector obstacles = canvas->data->GetObstacles(); FOR(i, count) { QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h); sample = canvas->toSampleCoords(samplePre); float color = (rand()/(float)RAND_MAX*0.7f)*255.f; color = 0; QPointF oldPoint = canvas->toCanvasCoords(sample); FOR(j, steps) { fvec res = dynamical->Test(sample); if(dynamical->avoid) { dynamical->avoid->SetObstacles(obstacles); fvec newRes = dynamical->avoid->Avoid(sample, res); res = newRes; } sample += res*dT; float speed = sqrtf(res[0]*res[0] + res[1]*res[1]); QPointF point = canvas->toCanvasCoords(sample); painter.setOpacity(speed); QColor c(color,color,color); painter.setPen(QPen(c, 0.25)); painter.drawLine(point, oldPoint); oldPoint = point; } } } mldemos-0.4.3/Core/drawSVG.h000066400000000000000000000035541172143270300155430ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _DRAWSVG_H_ #define _DRAWSVG_H_ #include #include #include "canvas.h" #include "classifier.h" #include "regressor.h" #include "dynamical.h" #include "clusterer.h" #include "maximize.h" #include "interfaces.h" #include #include class DrawSVG { private: u32 *perm; Canvas *canvas; int w, h; public: DrawSVG(Canvas *canvas, QMutex *mutex); ~DrawSVG(); void Write(QString filename); void Vectors(int count, int steps, QPainter &painter); void VectorsFast(int count, int steps, QPainter &painter); void Maximization(QPainter &painter); Classifier *classifier; Regressor *regressor; Dynamical *dynamical; Clusterer *clusterer; Maximizer *maximizer; Projector *projector; ClassifierInterface *drawClass; RegressorInterface *drawRegr; DynamicalInterface *drawDyn; ClustererInterface *drawClust; ProjectorInterface *drawProj; QMutex *mutex; }; #endif // _DRAWSVG_H_ mldemos-0.4.3/Core/drawTimer.cpp000066400000000000000000000257761172143270300165310ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include #include #include #include #include #include #include "public.h" #include "basicMath.h" #include "drawTimer.h" using namespace std; DrawTimer::DrawTimer(Canvas *canvas, QMutex *mutex) : canvas(canvas), refineLevel(0), refineMax(10), classifier(0), regressor(0), dynamical(0), clusterer(0), bRunning(false), bPaused(false), bColorMap(true), mutex(mutex), perm(0), w(0), h(0), dim(2) { } DrawTimer::~DrawTimer() { KILL(perm); } void DrawTimer::Stop() { bRunning = false; } void DrawTimer::Clear() { refineLevel = 0; w = canvas->width(); h = canvas->height(); drawMutex.lock(); bigMap = QImage(QSize(w,h), QImage::Format_ARGB32); bigMap.fill(0xffffff); modelMap = QImage(QSize(w,h), QImage::Format_ARGB32); modelMap.fill(qRgba(255, 255, 255, 0)); KILL(perm); perm = randPerm(w*h); drawMutex.unlock(); } void DrawTimer::run() { bRunning = true; while(bRunning) { if(!canvas || canvas->canvasType) break; if((!classifier || !(*classifier)) && (!regressor || !(*regressor)) && (!dynamical || !(*dynamical)) && (!clusterer || !(*clusterer)) && (!maximizer || !(*maximizer))) { //if(refineLevel) Clear(); Clear(); bRunning = false; return; } // we refine the current map Refine(); // and we send the image to the canvas drawMutex.lock(); //emit MapReady(bigMap); //if(dynamical && (*dynamical) || maximizer && (*maximizer) ) emit ModelReady(modelMap); if(maximizer && (*maximizer)) { emit ModelReady(modelMap); emit CurveReady(); //canvas->SetModelImage(modelMap); } else { if(dynamical && (*dynamical)) emit bColorMap ? MapReady(bigMap) : MapReady(modelMap); else emit MapReady(bigMap); } drawMutex.unlock(); //qApp->processEvents(); this->msleep(50); } bRunning = false; } void DrawTimer::Refine() { if(refineLevel > refineMax) { bRunning = false; return; } if(canvas->width() != w || canvas->height() != h) { Clear(); return; } if(refineLevel == 0) { Clear(); if(maximizer && (*maximizer)) { refineMax = 100; } else { refineMax = 20; } } else { int count = (w*h) / refineMax; int start = count * (refineLevel-1); int stop = count * refineLevel; if(refineLevel == refineMax) stop = w*h; // we want to be sure we paint everything in the end if(maximizer && (*maximizer)) { Maximization(); if((*maximizer)->hasConverged()) refineLevel=refineMax+1; else refineLevel = 1; return; } TestFast(start,stop); // we finish the current batch if(dynamical && (*dynamical) && !bColorMap) { int cnt = 10000 / refineMax; int steps = 8; VectorsFast(cnt, steps); } } refineLevel++; } void DrawTimer::Vectors(int count, int steps) { if(!bRunning || !mutex) return; mutex->lock(); if(!(*dynamical)) return; float dT = (*dynamical)->dT;// * (dynamical->count/100.f); mutex->unlock(); //float dT = 0.02f; fvec sample; sample.resize(2,0); int w = canvas->width(); int h = canvas->height(); QMutexLocker drawLock(&drawMutex); QPainter painter(&modelMap); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); vector obstacles = canvas->data->GetObstacles(); QPointF oldPoint(-FLT_MAX,-FLT_MAX); QPointF oldPointUp(-FLT_MAX,-FLT_MAX); QPointF oldPointDown(-FLT_MAX,-FLT_MAX); FOR(i, count) { QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h); sample = canvas->toSampleCoords(samplePre); float color = (rand()/(float)RAND_MAX*0.7f)*255.f; color = 0; QPointF oldPoint = canvas->toCanvasCoords(sample); FOR(j, steps) { if(!(*dynamical)) return; mutex->lock(); fvec res = (*dynamical)->Test(sample); if((*dynamical)->avoid) { (*dynamical)->avoid->SetObstacles(obstacles); fvec newRes = (*dynamical)->avoid->Avoid(sample, res); res = newRes; } mutex->unlock(); sample += res*dT; float speed = sqrtf(res[0]*res[0] + res[1]*res[1]); QPointF point = canvas->toCanvasCoords(sample); painter.setOpacity(speed); QColor c(color,color,color); painter.setPen(QPen(c, 0.25)); painter.drawLine(point, oldPoint); oldPoint = point; } } } void DrawTimer::Maximization() { if(!maximizer || !(*maximizer)) return; QMutexLocker lock(mutex); if(!bRunning) return; fvec sample = (*maximizer)->Test((*maximizer)->Maximum()); double value = (*maximizer)->MaximumValue(); if(value >= (*maximizer)->stopValue) { (*maximizer)->SetConverged(true); } if((*maximizer)->age >= (*maximizer)->maxAge) { (*maximizer)->SetConverged(true); } else (*maximizer)->age++; QMutexLocker drawLock(&drawMutex); int w = modelMap.width(); int h = modelMap.height(); if(modelMap.isNull() || !w || !h) return; modelMap.fill(qRgba(255, 255, 255, 0)); QPainter painter(&modelMap); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); (*maximizer)->Draw(painter); QPointF point(sample[0]*w, sample[1]*h); painter.setPen(QPen(Qt::black, 1.5)); painter.setBrush(Qt::NoBrush); painter.drawEllipse(point, 3, 3); } void DrawTimer::VectorsFast(int count, int steps) { if(!(*dynamical)) return; if(!bRunning || !mutex) return; QPointF oldPoint(-FLT_MAX,-FLT_MAX); QPointF oldPointUp(-FLT_MAX,-FLT_MAX); QPointF oldPointDown(-FLT_MAX,-FLT_MAX); mutex->lock(); float dT = (*dynamical)->dT;// * (dynamical->count/100.f); mutex->unlock(); //float dT = 0.02f; fvec sample; sample.resize(2,0); int w = canvas->width(); int h = canvas->height(); QMutexLocker drawLock(&drawMutex); QPainter painter(&modelMap); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); vector obstacles = canvas->data->GetObstacles(); FOR(i, count) { QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h); sample = canvas->toSampleCoords(samplePre); float color = (rand()/(float)RAND_MAX*0.7f)*255.f; color = 0; QPointF oldPoint = canvas->toCanvasCoords(sample); FOR(j, steps) { if(!(*dynamical)) return; mutex->lock(); fvec res = (*dynamical)->Test(sample); if((*dynamical)->avoid) { (*dynamical)->avoid->SetObstacles(obstacles); fvec newRes = (*dynamical)->avoid->Avoid(sample, res); res = newRes; } mutex->unlock(); sample += res*dT; float speed = sqrtf(res[0]*res[0] + res[1]*res[1]); QPointF point = canvas->toCanvasCoords(sample); painter.setOpacity(speed); QColor c(color,color,color); painter.setPen(QPen(c, 0.25)); painter.drawLine(point, oldPoint); oldPoint = point; } } } QColor DrawTimer::GetColor(Classifier *classifier, fvec sample) { QColor c; if(classifier->IsMultiClass()) { fvec val = classifier->TestMulti(sample); if(val.size() == 1) { float v = val[0]; int color = fabs(v)*128; color = max(0,min(color, 255)); if(v > 0) c = QColor(color,0,0); else c = QColor(color,color,color); } else { // we find the max int maxVal = 0; FOR(i, val.size()) if (val[maxVal] < val[i]) maxVal = i; val[maxVal] *= 3; float sum = 0; FOR(i, val.size()) sum += fabs(val[i]); sum = 1.f/sum; float r=0,g=0,b=0; FOR(j, val.size()) { int index = classifier->inverseMap[j]; r += SampleColor[index%SampleColorCnt].red()*val[j]*sum; g += SampleColor[index%SampleColorCnt].green()*val[j]*sum; b += SampleColor[index%SampleColorCnt].blue()*val[j]*sum; } c = QColor(max(0.f,min(255.f,r)),max(0.f,min(255.f,g)),max(0.f,min(255.f,b))); } } else { float v = classifier->Test(sample); int color = (int)(fabs(v)*128); color = max(0,min(color, 255)); if(v > 0) c = QColor(color,0,0); else c = QColor(color,color,color); } return c; } void DrawTimer::TestFast(int start, int stop) { if(stop < 0 || stop > w*h) stop = w*h; mutex->lock(); int dim=canvas->data->GetDimCount(); vector obstacles = canvas->data->GetObstacles(); mutex->unlock(); if(dim > 2) return; // we dont want to draw multidimensional stuff, it's ... problematic fvec sample(dim); for (int i=start; i= bigMap.width() || y >= bigMap.height()) continue; drawMutex.unlock(); sample = canvas->fromCanvas(x,y); fvec val(dim); float v; QMutexLocker lock(mutex); if((*classifier)) { QColor c = GetColor(*classifier, sample); drawMutex.lock(); bigMap.setPixel(x,y,c.rgb()); drawMutex.unlock(); } else if(*regressor) { val = (*regressor)->Test(sample); } else if(*clusterer) { fvec res = (*clusterer)->Test(sample); float r=0,g=0,b=0; if(res.size() > 1) { FOR(i, res.size()) { r += SampleColor[(i+1)%SampleColorCnt].red()*res[i]; g += SampleColor[(i+1)%SampleColorCnt].green()*res[i]; b += SampleColor[(i+1)%SampleColorCnt].blue()*res[i]; } } else if(res.size()) { r = (1-res[0])*255 + res[0]* 255; g = (1-res[0])*255; b = (1-res[0])*255; } if( r < 10 && g < 10 && b < 10) r = b = g = 255; QColor c = QColor(r,g,b); drawMutex.lock(); bigMap.setPixel(x,y,c.rgb()); drawMutex.unlock(); } else if(*dynamical && bColorMap) { val = (*dynamical)->Test(sample); if((*dynamical)->avoid) { (*dynamical)->avoid->SetObstacles(obstacles); fVec newRes = (*dynamical)->avoid->Avoid(sample, val); val = newRes; } float speed = sqrtf(val[0]*val[0] + val[1]*val[1]); speed = min(1.f,speed); int hue = (int)((atan2(val[0], val[1]) / (2*M_PI) + 0.5) * 359); QColor color = QColor::fromHsv(hue, 255, 255); color.setRed(255*(1-speed) + color.red()*speed); color.setGreen(255*(1-speed) + color.green()*speed); color.setBlue(255*(1-speed) + color.blue()*speed); drawMutex.lock(); bigMap.setPixel(x,y,color.rgb()); drawMutex.unlock(); } } } mldemos-0.4.3/Core/drawTimer.h000066400000000000000000000037741172143270300161700ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _DRAWTIMER_H_ #define _DRAWTIMER_H_ #include #include #include "canvas.h" #include "classifier.h" #include "regressor.h" #include "dynamical.h" #include "clusterer.h" #include "maximize.h" #include #include class DrawTimer : public QThread { Q_OBJECT private: int refineLevel; int refineMax; QImage bigMap; QImage modelMap; u32 *perm; Canvas *canvas; int w, h, dim; public: DrawTimer(Canvas *canvas, QMutex *mutex); ~DrawTimer(); void run(); void Refine(); void Clear(); void TestFast(int start, int stop); void Vectors(int count, int steps); void VectorsFast(int count, int steps); void Maximization(); void Stop(); static QColor GetColor(Classifier *classifier, fvec sample); Classifier **classifier; Regressor **regressor; Dynamical **dynamical; Clusterer **clusterer; Maximizer **maximizer; QMutex *mutex, drawMutex; bool bPaused; bool bRunning; bool bColorMap; signals: void MapReady(QImage image); void ModelReady(QImage image); void CurveReady(); }; #endif // _DRAWTIMER_H_ mldemos-0.4.3/Core/drawUtils.cpp000066400000000000000000000403601172143270300165330ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "drawUtils.h" #include "basicMath.h" #include using namespace std; #define RES 256 void DrawEllipse(float *mean, float *sigma, float rad, QPainter *painter, QSize size) { if(mean[0] != mean[0] || mean[1] != mean[1]) return; // nan float a = sigma[0], b = sigma[1], c = sigma[2]; float L[4]; L[0] = a; L[1] = 0; L[2] = b; L[3] = sqrtf(c*a-b*b); if(L[3] != L[3]) L[3] = 0; FOR(i,4) L[i] /= sqrtf(a); const int segments = 64; float oldX = FLT_MAX, oldY = FLT_MAX; for (float theta=0; theta <= PIf*2.f; theta += (PIf*2.f)/segments) { float x = cosf(theta)*rad; float y = sinf(theta)*rad; float nx = L[0]*x; float ny = L[2]*x + L[3]*y; nx += mean[0]; ny += mean[1]; if(oldX != FLT_MAX) { painter->drawLine( QPointF(nx*size.width(),ny*size.height()), QPointF(oldX*size.width(),oldY*size.height()) ); } oldX = nx; oldY = ny; } } void DrawEllipse(float *mean, float *sigma, float rad, QPainter *painter, Canvas *canvas) { if(mean[0] != mean[0] || mean[1] != mean[1]) return; // nan float a = sigma[0], b = sigma[1], c = sigma[2]; float L[4]; L[0] = a; L[1] = 0; L[2] = b; L[3] = sqrtf(c*a-b*b); if(L[3] != L[3]) L[3] = 0; FOR(i,4) L[i] /= sqrtf(a); const int segments = 64; float oldX = FLT_MAX, oldY = FLT_MAX; for (float theta=0; theta <= PIf*2.f; theta += (PIf*2.f)/segments) { float x = cosf(theta)*rad; float y = sinf(theta)*rad; float nx = L[0]*x; float ny = L[2]*x + L[3]*y; nx += mean[0]; ny += mean[1]; if(oldX != FLT_MAX) { painter->drawLine(canvas->toCanvasCoords(nx,ny), canvas->toCanvasCoords(oldX, oldY)); } oldX = nx; oldY = ny; } } void DrawArrow( const QPointF &ppt, const QPointF &pt, double sze, QPainter &painter) { QPointF pd, pa, pb; double tangent; pd = ppt - pt; if (pd.x() == 0 && pd.y() == 0) return; tangent = atan2 ((double) pd.y(), (double) pd.x()); pa.setX(sze * cos (tangent + PIf / 7.f) + pt.x()); pa.setY(sze * sin (tangent + PIf / 7.f) + pt.y()); pb.setX(sze * cos (tangent - PIf / 7.f) + pt.x()); pb.setY(sze * sin (tangent - PIf / 7.f) + pt.y()); //-- connect the dots... painter.drawLine(pt, ppt); painter.drawLine(pt, pa); painter.drawLine(pt, pb); } QColor ColorFromVector(fvec a) { // angle is between 0 and 1; float angle = atan2(a[0], a[1]) / (2*PIf) + 0.5f; vector colors; #define Col2Col(r,g,b) {fvec c;c.resize(3); c[0] = r;c[1] = g;c[2] = b; colors.push_back(c);} Col2Col(0,0,255); Col2Col(255,0,255); Col2Col(255,0,0); Col2Col(255,255,0); Col2Col(0,255,0); Col2Col(0,255,255); // find where the angle fits in the color list int index = (int)(angle*(colors.size())) % colors.size(); fvec c1 = colors[index]; fvec c2 = colors[(index+1)%colors.size()]; // compute the ratio between c1 and c2 float remainder = angle*(colors.size()) - (int)(angle*(colors.size())); fvec c3 = c1*(1-remainder) + c2*remainder; return QColor(c3[0],c3[1],c3[2]); } QPixmap RocImage(std::vector< std::vector > rocdata, std::vector roclabels, QSize size) { QPixmap pixmap(size); pixmap.fill(Qt::white); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); int w = pixmap.width(), h = pixmap.height(); int PAD = 16; QFont font = painter.font(); font.setPointSize(12); font.setBold(true); painter.setFont(font); FOR(d, rocdata.size()) { int minCol = 128; int color = (rocdata.size() == 1) ? 255 : (255 - minCol)*(rocdata.size() - d -1)/(rocdata.size()-1) + minCol; color = 255 - color; std::vector data = rocdata[d]; if(!data.size()) continue; std::sort(data.begin(), data.end()); std::vector allData; FOR(i, data.size()) { float thresh = data[i].first; u32 tp = 0, fp = 0; u32 fn = 0, tn = 0; FOR(j, data.size()) { if(data[j].second == 1) { if(data[j].first >= thresh) tp++; else fn++; } else { if(data[j].first >= thresh) fp++; else tn++; } } fVec val; float fmeasure = 0; if((fp+tn)>0 && (tp+fn)>0 && (tp+fp)>0) { val=fVec(fp/float(fp+tn), 1 - tp/float(tp+fn)); float precision = tp / float(tp+fp); float recall = tp /float(tp+fn); fmeasure = tp == 0 ? 0 : 2 * (precision * recall) / (precision + recall); } fvec dat; dat.push_back(val.x); dat.push_back(val.y); dat.push_back(data[i].first); dat.push_back(fmeasure); allData.push_back(dat); } painter.setPen(QPen(QColor(color,color,color), 1.f)); fVec pt1, pt2; FOR(i, allData.size()-1) { pt1 = fVec(allData[i][0]*size.width(), allData[i][1]*size.height()); pt2 = fVec(allData[i+1][0]*size.width(), allData[i+1][1]*size.height()); painter.drawLine(QPointF(pt1.x+PAD, pt1.y+PAD),QPointF(pt2.x+PAD, pt2.y+PAD)); } pt1 = fVec(0,size.width()); painter.drawLine(QPointF(pt1.x+PAD, pt1.y+PAD),QPointF(pt2.x+PAD, pt2.y+PAD)); if(d < roclabels.size()) { QPointF pos(3*size.width()/4,size.height() - (d+1)*16); painter.drawText(pos,QString(roclabels[d])); } } font = painter.font(); font.setPointSize(10); font.setBold(false); font.setCapitalization(QFont::SmallCaps); painter.setFont(font); painter.setPen(Qt::black); painter.drawText(0, 0, size.width(), 16, Qt::AlignCenter, "False Positives"); painter.translate(0, size.height()); painter.rotate(-90); painter.drawText(0,0, size.height(), 16, Qt::AlignCenter, "True Positives"); return pixmap; } QPixmap BoxPlot(std::vector allData, QSize size, float maxVal, float minVal) { QPixmap boxplot(size); if(!allData.size()) return boxplot; QBitmap bitmap; bitmap.clear(); boxplot.setMask(bitmap); boxplot.fill(Qt::transparent); QPainter painter(&boxplot); // painter.setRenderHint(QPainter::Antialiasing); FOR(d,allData.size()) { fvec data = allData[d]; if(!data.size()) continue; FOR(i, data.size()) maxVal = max(maxVal, data[i]); FOR(i, data.size()) minVal = min(minVal, data[i]); } if(minVal == maxVal) { minVal = minVal/2; minVal = minVal*3/2; } FOR(d,allData.size()) { int minCol = 70; int color = (allData.size() == 1) ? minCol : (255-minCol) * d / allData.size() + minCol; fvec data = allData[d]; if(!data.size()) continue; int hpad = 15 + (d*size.width()/(allData.size())); int pad = -16; int res = size.height()+2*pad; int nanCount = 0; FOR(i, data.size()) if(data[i] != data[i]) nanCount++; float mean = 0; float sigma = 0; FOR(i, data.size()) if(data[i]==data[i]) mean += data[i] / (data.size()-nanCount); FOR(i, data.size()) if(data[i]==data[i]) sigma += powf(data[i]-mean,2); sigma = sqrtf(sigma/(data.size()-nanCount)); float edge = minVal; float delta = maxVal - minVal; float top, bottom, median, quartLow, quartHi; vector outliers; vector sorted; if(data.size() > 1) { if(sigma==0) { sorted = data; } else { // we look for outliers using the 3*sigma rule FOR(i, data.size()) { if(data[i]!=data[i]) continue; if (data[i] - mean < 3*sigma) sorted.push_back(data[i]); else outliers.push_back(data[i]); } } if(!sorted.size()) return boxplot; sort(sorted.begin(), sorted.end()); int count = sorted.size(); int half = count/2; bottom = sorted[0]; top = sorted[sorted.size()-1]; median = count%2 ? sorted[half] : (sorted[half] + sorted[half - 1])/2; quartLow, quartHi; if(count < 4) { quartLow = bottom; quartHi = top; } else { quartLow = half%2 ? sorted[half/2] : (sorted[half/2] + sorted[half/2 - 1])/2; quartHi = half%2 ? sorted[half*3/2] : (sorted[half*3/2] + sorted[half*3/2 - 1])/2; } } else { top = bottom = median = quartLow = quartHi = data[0]; } QPointF bottomPoint = QPointF(0, size.height() - (int)((bottom-edge)/delta*res) + pad); QPointF topPoint = QPointF(0, size.height() - (int)((top-edge)/delta*res) + pad); QPointF medPoint = QPointF(0, size.height() - (int)((median-edge)/delta*res) + pad); QPointF lowPoint = QPointF(0, size.height() - (int)((quartLow-edge)/delta*res) + pad); QPointF highPoint = QPointF(0, size.height() - (int)((quartHi-edge)/delta*res) + pad); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+35, bottomPoint.y()), QPointF(hpad+65, bottomPoint.y())); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+35, topPoint.y()), QPointF(hpad+65, topPoint.y())); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+50, bottomPoint.y()), QPointF(hpad+50, topPoint.y())); painter.setBrush(QColor(color,color,color)); painter.drawRect(hpad+30, lowPoint.y(), 40, highPoint.y() - lowPoint.y()); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+30, medPoint.y()), QPointF(hpad+70, medPoint.y())); const char *longFormat = "%.3f"; const char *shortFormat = "%.0f"; const char *format = (maxVal - minVal) > 100 ? shortFormat : longFormat; painter.setPen(Qt::black); char text[255]; sprintf(text, format, median); painter.drawText(QPointF(hpad-8,medPoint.y()+6), QString(text)); sprintf(text, format, top); painter.drawText(QPointF(hpad+36,topPoint.y()-6), QString(text)); sprintf(text, format, bottom); painter.drawText(QPointF(hpad+36,bottomPoint.y()+12), QString(text)); } return boxplot; } QPixmap Histogram(std::vector allData, QSize size, float maxVal, float minVal) { QPixmap histogram(size); if(!allData.size()) return histogram; QBitmap bitmap; bitmap.clear(); histogram.setMask(bitmap); histogram.fill(Qt::transparent); QPainter painter(&histogram); // painter.setRenderHint(QPainter::Antialiasing); FOR(d,allData.size()) { fvec data = allData[d]; if(!data.size()) continue; FOR(i, data.size()) if(data[i]==data[i]) maxVal = max(maxVal, data[i]); FOR(i, data.size()) if(data[i]==data[i]) minVal = min(minVal, data[i]); } if(minVal == maxVal) { minVal = minVal/2; minVal = minVal*3/2; } FOR(d,allData.size()) { int minCol = 70; int color = (allData.size() == 1) ? minCol : (255-minCol) * d / allData.size() + minCol; fvec data = allData[d]; if(!data.size()) continue; int hpad = 15 + (d*size.width()/(allData.size())); int pad = -16; int res = size.height()+2*pad; int nanCount = 0; FOR(i, data.size()) if(data[i] != data[i]) nanCount++; float mean = 0; float sigma = 0; FOR(i, data.size()) if(data[i]==data[i]) mean += data[i] / (data.size()-nanCount); FOR(i, data.size()) if(data[i]==data[i]) sigma += powf(data[i]-mean,2); sigma = sqrtf(sigma/(data.size()-nanCount)); float edge = minVal; float delta = maxVal - minVal; float bottom = 0; QPointF bottomPoint = QPointF(0, size.height() - (int)((bottom-edge)/delta*res) + pad); QPointF topPoint = QPointF(0, size.height() - (int)((mean-edge)/delta*res) + pad); QPointF plusPoint = QPointF(0, size.height() - (int)((mean+sigma-edge)/delta*res) + pad); QPointF minusPoint = QPointF(0, size.height() - (int)((mean-sigma-edge)/delta*res) + pad); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+35, bottomPoint.y()), QPointF(hpad+65, bottomPoint.y())); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+35, topPoint.y()), QPointF(hpad+65, topPoint.y())); painter.setBrush(QColor(color,color,color)); painter.drawRect(hpad+30, topPoint.y(), 40, bottomPoint.y()-topPoint.y()); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+50, plusPoint.y()), QPointF(hpad+50, minusPoint.y())); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+40, plusPoint.y()), QPointF(hpad+60, plusPoint.y())); painter.setPen(Qt::black); painter.drawLine(QPointF(hpad+40, minusPoint.y()), QPointF(hpad+60, minusPoint.y())); const char *longFormat = "%.3f"; const char *shortFormat = "%.0f"; const char *format = (maxVal - minVal) > 10 ? shortFormat : longFormat; painter.setPen(Qt::black); char text[255]; sprintf(text, format, mean); painter.drawText(QPointF(hpad-8,topPoint.y()+6), QString(text)); sprintf(text, format, mean+sigma); painter.drawText(QPointF(hpad+36,plusPoint.y()-6), QString(text)); sprintf(text, format, mean-sigma); painter.drawText(QPointF(hpad+36,minusPoint.y()+12), QString(text)); } return histogram; } QPixmap RawData(std::vector allData, QSize size, float maxVal, float minVal) { QPixmap rawData(size); if(!allData.size()) return rawData; QBitmap bitmap; bitmap.clear(); rawData.setMask(bitmap); rawData.fill(Qt::transparent); QPainter painter(&rawData); painter.setRenderHint(QPainter::Antialiasing); FOR(d,allData.size()) { fvec data = allData[d]; if(!data.size()) continue; FOR(i, data.size()) if(data[i]==data[i]) maxVal = max(maxVal, data[i]); FOR(i, data.size()) if(data[i]==data[i]) minVal = min(minVal, data[i]); } if(minVal == maxVal) { minVal = minVal/2; minVal = minVal*3/2; } FOR(d,allData.size()) { int minCol = 70; int color = (allData.size() == 1) ? minCol : (255-minCol) * d / allData.size() + minCol; fvec data = allData[d]; if(!data.size()) continue; int hpad = 15 + (d*size.width()/(allData.size())); int hsize = (size.width()/allData.size() - 15); int pad = -16; int res = size.height()+2*pad; int nanCount = 0; FOR(i, data.size()) if(data[i] != data[i]) nanCount++; float mean = 0; float sigma = 0; FOR(i, data.size()) if(data[i]==data[i]) mean += data[i] / (data.size()-nanCount); FOR(i, data.size()) if(data[i]==data[i]) sigma += powf(data[i]-mean,2); sigma = sqrtf(sigma/(data.size()-nanCount)); float edge = minVal; float delta = maxVal - minVal; QPointF topPoint = QPointF(0, size.height() - (int)((mean-edge)/delta*res) + pad); QPointF plusPoint = QPointF(0, size.height() - (int)((mean+sigma-edge)/delta*res) + pad); QPointF minusPoint = QPointF(0, size.height() - (int)((mean-sigma-edge)/delta*res) + pad); FOR(i, data.size()) { QPointF point = QPointF(hpad + (drand48() - 0.5)*hsize/2 + hsize/2, size.height() - (int)((data[i]-edge)/delta*res) + pad); painter.setPen(QPen(Qt::black, 0.5)); painter.setBrush(QColor(color,color,color)); painter.drawEllipse(point, 5, 5); } const char *longFormat = "%.3f"; const char *shortFormat = "%.0f"; const char *format = (maxVal - minVal) > 10 ? shortFormat : longFormat; painter.setPen(Qt::black); char text[255]; sprintf(text, format, mean); painter.drawText(QPointF(hpad-8,topPoint.y()+6), QString(text)); sprintf(text, format, mean+sigma); painter.drawText(QPointF(hpad-8,plusPoint.y()-6), QString(text)); sprintf(text, format, mean-sigma); painter.drawText(QPointF(hpad-8,minusPoint.y()+12), QString(text)); } return rawData; } mldemos-0.4.3/Core/drawUtils.h000066400000000000000000000034611172143270300162010ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _DRAW_UTILS_H_ #define _DRAW_UTILS_H_ #include "public.h" #include "mymaths.h" #include "basicMath.h" #include "canvas.h" #include "roc.h" #include void DrawEllipse(float *mean, float *sigma, float rad, QPainter *painter, QSize size); void DrawEllipse(float *mean, float *sigma, float rad, QPainter *painter, Canvas *canvas); void DrawArrow( const QPointF &ppt, const QPointF &pt, double sze, QPainter &painter); QColor ColorFromVector(fvec a); QPixmap RocImage(std::vector< std::vector > rocdata, std::vector roclabels, QSize size); QPixmap BoxPlot(std::vector allData, QSize size, float maxVal=-FLT_MAX, float minVal=FLT_MAX); QPixmap Histogram(std::vector allData, QSize size, float maxVal=-FLT_MAX, float minVal=FLT_MAX); QPixmap RawData(std::vector allData, QSize size, float maxVal=-FLT_MAX, float minVal=FLT_MAX); #endif // _DRAW_UTILS_H_ mldemos-0.4.3/Core/dynamical.h000066400000000000000000000040151172143270300161600ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _DYNAMICAL_H_ #define _DYNAMICAL_H_ #include "mymaths.h" #include "obstacles.h" #include extern "C" enum {DYN_SVR, DYN_RVM, DYN_GMR, DYN_GPR, DYN_KNN, DYN_MLP, DYN_LINEAR, DYN_LWPR, DYN_KRLS, DYN_SEDS, DYN_NONE} dynamicalType; class Dynamical { protected: std::vector< std::vector > trajectories; ivec classes; ivec labels; u32 dim; public: std::vector crossval; fvec fmeasures; fvec trainErrors, testErrors; int type; float dT; u32 count; ObstacleAvoidance *avoid; Dynamical(): type(DYN_NONE), count(100), dT(0.02f), avoid(0){} ~Dynamical(){if(avoid) delete avoid;}; std::vector< std::vector > GetTrajectories(){return trajectories;}; int Dim(){return dim;}; virtual void Train(std::vector< std::vector > trajectories, ivec labels){}; virtual std::vector Test( const fvec &sample, const int count){ return std::vector(); }; virtual fvec Test( const fvec &sample){ return fvec(); }; virtual fVec Test(const fVec &sample){ return fVec(Test((fvec)sample)); }; virtual char *GetInfoString(){return NULL;}; }; #endif // _DYNAMICAL_H_ mldemos-0.4.3/Core/expose.cpp000066400000000000000000000704351172143270300160660ustar00rootroot00000000000000#include #include #include #include "expose.h" #include "ui_expose.h" #include #include #include using namespace std; Expose::Expose(Canvas *canvas, QWidget *parent) : QWidget(parent), ui(new Ui::Expose), canvas(canvas) { ui->setupUi(this); connect(ui->typeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(Repaint())); connect(ui->clipboardButton, SIGNAL(clicked()), this, SLOT(Clipboard())); this->setWindowTitle("Multivariate Visualisation"); } Expose::~Expose() { delete ui; } void Expose::DrawData(QPixmap& pixmap, std::vector samples, ivec labels, std::vector flags, int type, bool bProjected, QStringList names, std::pair bounds) { if(!samples.size() || !labels.size()) return; vector sampleColors(labels.size()); FOR(i, labels.size()) { QColor color = SampleColor[labels[i]%SampleColorCnt]; sampleColors[i] = color; } DrawData(pixmap, samples, sampleColors, flags, type, bProjected, false, names, bounds); } void Expose::DrawData(QPixmap& pixmap, std::vector samples, std::vector sampleColors, std::vector flags, int type, bool bProjected, bool bLearned, QStringList names, std::pair bounds) { if(!samples.size()) return; int w = pixmap.width(), h = pixmap.height(); int dim = samples[0].size(); int gridX = dim; int gridY = dim; fvec mins = bounds.first; fvec maxes = bounds.second; if(!bounds.first.size()) { mins.resize(dim, FLT_MAX); maxes.resize(dim, -FLT_MIN); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } bounds.first = mins; bounds.second = maxes; } fvec diffs(dim, 0); FOR(d, dim) { diffs[d] = maxes[d] - mins[d]; } int pad = 20; int mapW = w - pad*2, mapH = h - pad*2; QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); switch(type) { case 0: // scatterplots { mapW = w/gridX - pad*2; mapH = h/gridX - pad*2; int radiusBase = max(5.f, 5 * sqrtf(mapW / 200.f)); QList maps; FOR(index0, dim) { FOR(index1, dim) { QPixmap map(mapW + 2*pad,mapH + 2*pad); int smallW = map.width() - 2*pad, smallH = map.height() - 2*pad; if(!bLearned) map.fill(Qt::white); else { QBitmap bitmap(map.size()); bitmap.clear(); map.setMask(bitmap); map.fill(Qt::transparent); } QPainter painter(&map); painter.setRenderHint(QPainter::Antialiasing); if(diffs[index0] != 0.f && diffs[index1] != 0.f) { FOR(i, samples.size()) { if(flags[i] == _TRAJ || flags[i] == _OBST) continue; float x = samples[i][index0]; float y = samples[i][index1]; x = (x-mins[index0])/diffs[index0]; y = (y-mins[index1])/diffs[index1]; QPointF point(y*smallW + pad, x*smallH + pad); float radius = radiusBase; if(bLearned) { radius = radiusBase + radiusBase/2; if(i < sampleColors.size()) painter.setPen(QPen(sampleColors[i], radiusBase/2)); painter.setBrush(Qt::NoBrush); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); radius += radiusBase/2-1; painter.setPen(QPen(Qt::black, 0.5)); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); } else { if(i < sampleColors.size()) painter.setBrush(sampleColors[i]); painter.setPen(Qt::black); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); } } } painter.setBrush(Qt::NoBrush); painter.setPen(Qt::black); painter.setRenderHint(QPainter::Antialiasing, false); painter.drawRect(pad/2,pad/2,smallW+pad, smallH+pad); QString text = QString("x%1 x%2").arg(index1+1).arg(index0+1); if(index0 < names.size() && index1 < names.size()) text = names.at(index1) + " " + names.at(index0); if(bProjected) text = QString("e%1 e%2").arg(index1+1).arg(index0+1); painter.drawText(pad/2+1, map.height()-pad/2-1,text); maps.push_back(map); } } FOR(i, maps.size()) { int xIndex = i%gridX; int yIndex = i/gridX; painter.drawPixmap(QPoint(xIndex*w/gridX, yIndex*h/gridY), maps[i]); } } break; case 1: // parallel coordinates { painter.setRenderHint(QPainter::Antialiasing, false); FOR(d, dim) { float x = d*mapW/(float)(dim-1) + pad; painter.setPen(Qt::black); painter.drawLine(x, pad, x, mapH+pad); QString text = QString("x%1").arg(d+1); if(d < names.size()) text = names.at(d); if(bProjected) text = QString("e%1").arg(d+1); painter.drawText(x-10, mapH+2*pad-4, text); } painter.setRenderHint(QPainter::Antialiasing); FOR(i, samples.size()) { QPointF old; FOR(d, dim) { if(diffs[d] == 0.f) continue; float x = d*mapW/(float)(dim-1) + pad; float y = samples[i][d]; y = (y-mins[d])/(maxes[d] - mins[d]); QPointF point(x,pad + y*mapH); float radius = 7; QColor color = Qt::black; if(i < sampleColors.size()) color = sampleColors[i]; painter.setBrush(color); painter.setPen(Qt::black); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); if(color == Qt::white) color = Qt::black; painter.setPen(color); if(d) painter.drawLine(point, old); old = point; } } } break; case 2: // radial graphs { float radius = min(mapW, mapH)/3.f; QPointF center(mapW*0.5f, mapH*0.5f); QPointF old; painter.setPen(Qt::black); painter.setBrush(Qt::NoBrush); painter.drawEllipse(center, radius, radius); FOR(d, dim) { float theta = d/(float)(dim)*2*M_PI; QPointF point = QPointF(cos(theta), sin(theta))*radius; painter.setBrush(Qt::white); painter.drawEllipse(center+point, 4, 4); QString text = QString("x%1").arg(d+1); if(d < names.size()) text = names.at(d); if(bProjected) text = QString("e%1").arg(d+1); painter.drawText(center + point*1.1, text); old = point; } painter.setPen(Qt::black); FOR(i, samples.size()) { QPointF samplePoint; float dimSum = 0; FOR(d, dim) { if(diffs[d] == 0.f) continue; float theta = d/(float)(dim)*2*M_PI; QPointF point = QPointF(cos(theta), sin(theta))*radius; float value = (samples[i][d]-mins[d])/(maxes[d]-mins[d]); samplePoint += point*value; dimSum += value; } samplePoint /= dimSum; float drawRadius = 7; QPointF point = center + samplePoint; QColor color = Qt::black; if(i < sampleColors.size()) color = sampleColors[i]; painter.setBrush(color); painter.drawEllipse(QRectF(point.x()-drawRadius/2.,point.y()-drawRadius/2.,drawRadius,drawRadius)); } } break; case 3: // andrews plots { float radius = min(mapW, mapH)/3.f; QPointF center(mapW*0.5f, mapH*0.5f); painter.setPen(Qt::black); // f(t) = x0/sqrt(2) + x1*sin(t) + x2*cos(t) + x3*sin(2t) + x4*cos(2t) + x5*sin(3t) + x6*cos(3t) + x7*sin(4t) vector values(samples.size()); const int steps = 200; float minv=FLT_MAX, maxv=-FLT_MAX; FOR(i, samples.size()) { values[i].resize(steps); FOR(j, steps) { float t = j/(float)steps*(M_PI*2) - M_PI; float value = 0; FOR(d, dim) { if(diffs[d] == 0.f) continue; float v = (samples[i][d]-mins[d])/(maxes[d]-mins[d]); if(!d) value += v*sqrtf(2.f); else { value += v * (d%2 ? sin(t*((d+1)/2)) : cos(t*((d+1)/2))); } } values[i][j] = value; minv = min(minv, value); maxv = max(maxv, value); } } painter.setRenderHint(QPainter::Antialiasing, false); painter.setPen(Qt::black); painter.drawLine(pad, mapH-10+pad, mapW+pad, mapH-10+pad); QFont font = painter.font(); font.setPointSize(9); painter.setFont(font); QStringList ticks; ticks << "-pi" << "-pi/2" << "0" << "pi/2" << "pi"; FOR(i, 5) { int x = i*mapW/(4); painter.setRenderHint(QPainter::Antialiasing, false); painter.drawLine(pad + x, mapH-10 - 4 + pad, pad + x, mapH-10 + 4 + pad); painter.setRenderHint(QPainter::Antialiasing); painter.drawText(pad + x-25,mapH-10 + 4 + pad, 50, 20, Qt::AlignCenter, ticks[i]); } painter.setRenderHint(QPainter::Antialiasing); FOR(i, values.size()) { QColor color = Qt::black; if(i < sampleColors.size()) color = sampleColors[i]; if(color == Qt::white) color = Qt::black; painter.setPen(QPen(color,0.5)); QPointF old; FOR(j, values[i].size()) { float value = (values[i][j]-minv)/(maxv-minv); QPointF point = QPointF(j*pixmap.width()/steps, value*mapH + pad); if(j) painter.drawLine(point, old); old = point; } } } break; } } void Expose::DrawTrajectories(QPixmap& pixmap, vector< vector > trajectories, ivec labels, int type, int drawMode, std::pair bounds) { if(!trajectories.size() || !labels.size()) return; vector sampleColors(labels.size()); FOR(i, labels.size()) { QColor color = SampleColor[labels[i]%SampleColorCnt]; sampleColors[i] = color; } DrawTrajectories(pixmap, trajectories, sampleColors, type, drawMode, bounds); } void Expose::DrawTrajectories(QPixmap& pixmap, vector< vector > trajectories, std::vector sampleColors, int type, int drawMode, std::pair bounds) { if(!trajectories.size()) return; int w = pixmap.width(), h = pixmap.height(); int dim = trajectories[0][0].size()/2; // trajectories have velocity embedded so we only want half the dimensions if(!sampleColors.size()) dim = trajectories[0][0].size(); // unless we are actually drawing the trajectories without velocity int gridX = dim; int gridY = dim; fvec mins = bounds.first; fvec maxes = bounds.second; if(!bounds.first.size()) { mins.resize(dim, FLT_MAX); maxes.resize(dim, -FLT_MIN); FOR(d, dim) { FOR(i, trajectories.size()) { FOR(j, trajectories[i].size()) { mins[d] = min(mins[d], trajectories[i][j][d]); maxes[d] = max(maxes[d], trajectories[i][j][d]); } } } bounds.first = mins; bounds.second = maxes; } fvec diffs(dim, 0); FOR(d, dim) { diffs[d] = maxes[d] - mins[d]; } int pad = 20; int mapW = w - pad*2, mapH = h - pad*2; QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); if(type==0) { mapW = w/gridX - pad*2; mapH = h/gridX - pad*2; int radiusBase = max(4.f, 4 * sqrtf(mapW / 200.f)); QList maps; FOR(index0, dim) { FOR(index1, dim) { QPixmap map(mapW + 2*pad,mapH + 2*pad); int smallW = map.width() - 2*pad, smallH = map.height() - 2*pad; QBitmap bitmap(map.size()); bitmap.clear(); map.setMask(bitmap); map.fill(Qt::transparent); QPainter painter(&map); painter.setRenderHint(QPainter::Antialiasing); if(diffs[index0] != 0.f && diffs[index1] != 0.f) { int sampleColorCounter = 0; FOR(i, trajectories.size()) { QPointF oldPoint, firstPoint, point; int count = trajectories[i].size(); if(drawMode == 0 && i < sampleColors.size()) painter.setBrush(sampleColors[sampleColorCounter]); else painter.setBrush(Qt::black); FOR(j, count) { fvec pt = trajectories[i][j]; float x = pt[index0]; float y = pt[index1]; x = (x-mins[index0])/diffs[index0]; y = (y-mins[index1])/diffs[index1]; point = QPointF(y*smallW + pad, x*smallH + pad); if(drawMode == 0) painter.setPen(QPen(Qt::black, 0.5)); else if(drawMode == 1) painter.setPen(QPen(Qt::green, 1)); if(j) { painter.drawLine(point, oldPoint); if(j samples, ivec labels, int type, fvec params, bool bProjected, QStringList names) { if(!samples.size() || !labels.size()) return; vector sampleColors(labels.size()); FOR(i, labels.size()) { QColor color = SampleColor[labels[i]%SampleColorCnt]; sampleColors[i] = color; } DrawVariableData(pixmap, samples, sampleColors, type, params, bProjected, false, names); } void Expose::DrawVariableData(QPixmap& pixmap, std::vector samples, std::vector sampleColors, int type, fvec params, bool bProjected, bool bLearned, QStringList names) { if(!samples.size()) return; int w = pixmap.width(), h = pixmap.height(); int dim = samples[0].size(); int gridX = dim; int gridY = dim; fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN), diffs(dim, 0); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } FOR(d, dim) { diffs[d] = maxes[d] - mins[d]; } int pad = 20; int mapW = w - pad*2, mapH = h - pad*2; QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::black); switch(type) { case 0: // bubble graph { painter.setRenderHint(QPainter::Antialiasing, false); painter.drawLine(pad, mapH+pad, mapW+pad, mapH+pad); painter.drawLine(pad, pad, pad, mapH+pad); int xIndex = params[0]; int yIndex = params[1]; int sIndex = params[2]; if(sIndex == -1) { srand48(0); srand(0); } painter.setRenderHint(QPainter::Antialiasing); FOR(i, samples.size()) { float x = (samples[i][xIndex]-mins[xIndex])/(diffs[xIndex]); float y = (samples[i][yIndex]-mins[yIndex])/(diffs[yIndex]); QPointF point(x*mapW + pad,y*mapH + pad); float radius = 10; if(sIndex != -1) { radius = (samples[i][sIndex]-mins[sIndex])/(diffs[sIndex]); radius = radius*60 + 3; } else { radius = drand48()*40 + 3; } QColor color = Qt::black; if(i < sampleColors.size()) color = sampleColors[i]; painter.setBrush(color); painter.setPen(Qt::black); painter.setOpacity(0.5f); painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius)); } } break; } } void Expose::GenerateAndrewsPlots() { std::vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); if(!samples.size()) return; int dim = samples[0].size(); fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } int pad = 20; int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2; ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height()); pixmap.fill(Qt::white); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); float radius = min(mapW, mapH)/3.f; QPointF center(mapW*0.5f, mapH*0.5f); QPointF old; painter.setPen(Qt::black); // f(t) = x0/sqrt(2) + x1*sin(t) + x2*cos(t) + x3*sin(2t) + x4*cos(2t) + x5*sin(3t) + x6*cos(3t) + x7*sin(4t) vector values(samples.size()); const int steps = 200; float minv=FLT_MAX, maxv=-FLT_MAX; FOR(i, samples.size()) { values[i].resize(steps); FOR(j, steps) { float t = j/(float)steps*(M_PI*2) - M_PI; float value = 0; FOR(d, dim) { float v = (samples[i][d]-mins[d])/(maxes[d]-mins[d]); if(!d) value += v*sqrtf(2.f); else { value += v * (d%2 ? sin(t*((d+1)/2)) : cos(t*((d+1)/2))); } } values[i][j] = value; minv = min(minv, value); maxv = max(maxv, value); } } FOR(i, values.size()) { FOR(j, values[i].size()) { float value = (values[i][j]-minv)/(maxv-minv); QPointF point = QPointF(j*pixmap.width()/steps, value*mapH + pad); QColor color = SampleColor[labels[i]%SampleColorCnt]; painter.setPen(QPen(color,0.5)); if(j) painter.drawLine(point, old); old = point; } } ui->display->setPixmap(pixmap); ui->display->repaint(); } void Expose::GenerateRadialGraph() { std::vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); if(!samples.size()) return; int dim = samples[0].size(); fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } int pad = 20; int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2; ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height()); pixmap.fill(Qt::white); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); float radius = min(mapW, mapH)/3.f; QPointF center(mapW*0.5f, mapH*0.5f); QPointF old; painter.setPen(Qt::black); FOR(d, dim) { float theta = d/(float)(dim)*2*M_PI; QPointF point = QPointF(cos(theta), sin(theta))*radius; if(d) painter.drawLine(center + point, center + old); painter.drawText(center + point*1.1, QString("e%1").arg(d+1)); old = point; } painter.drawLine(center + QPointF(1.f, 0.f)*radius, center + old); painter.setRenderHint(QPainter::Antialiasing); FOR(i, samples.size()) { QPointF samplePoint; float dimSum = 0; FOR(d, dim) { float theta = d/(float)(dim)*2*M_PI; QPointF point = QPointF(cos(theta), sin(theta))*radius; float value = (samples[i][d]-mins[d])/(maxes[d]-mins[d]); samplePoint += point*value; dimSum += value; } samplePoint /= dimSum; float drawRadius = 7; Canvas::drawSample(painter, center + samplePoint, drawRadius, labels[i]); QColor color = SampleColor[labels[i]%SampleColorCnt]; painter.setPen(color); } ui->display->setPixmap(pixmap); ui->display->repaint(); } void Expose::GenerateParallelCoords() { std::vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); if(!samples.size()) return; int dim = samples[0].size(); fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } int pad = 20; int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2; ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height()); pixmap.fill(Qt::white); QPainter painter(&pixmap); FOR(d, dim) { float x = d*mapW/(float)(dim-1) + pad; painter.setPen(Qt::black); painter.drawLine(x, pad, x, mapH+pad); painter.drawText(x-10, mapH+2*pad-4, QString("e%1").arg(d+1)); } painter.setRenderHint(QPainter::Antialiasing); FOR(i, samples.size()) { QPointF old; FOR(d, dim) { float x = d*mapW/(float)(dim-1) + pad; float y = samples[i][d]; y = (y-mins[d])/(maxes[d] - mins[d]); QPointF point(x,pad + y*mapH); float radius = 7; Canvas::drawSample(painter, point, radius, labels[i]); QColor color = SampleColor[labels[i]%SampleColorCnt]; painter.setPen(color); if(d) painter.drawLine(point, old); old = point; } } ui->display->setPixmap(pixmap); ui->display->repaint(); } void Expose::GenerateScatterPlot(bool bCheckOnly) { std::vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); if(!samples.size()) return; int dim = samples[0].size(); bool bEvenCount = dim%2 == 1; int gridX = dim; int gridY = dim; fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN); FOR(d, dim) { FOR(i, samples.size()) { mins[d] = min(mins[d], samples[i][d]); maxes[d] = max(maxes[d], samples[i][d]); } } int pad = 20; int mapW = (ui->scrollArea->width()-12)/gridX - pad*2; int mapH = (ui->scrollArea->height()-12)/gridX - pad*2; bool bScroll = false; if(mapW < 100 || mapH < 100) { bScroll = true; mapW = max(mapW, 100); mapH = max(mapH, 100); } if(bScroll && bCheckOnly) return; QList maps; FOR(index0, dim) { FOR(index1, dim) { QPixmap map(mapW + 2*pad,mapH + 2*pad); int w = map.width() - 2*pad, h = map.height() - 2*pad; map.fill(Qt::white); QPainter painter(&map); painter.setRenderHint(QPainter::Antialiasing); FOR(i, samples.size()) { float x = samples[i][index0]; float y = samples[i][index1]; x = (x-mins[index0])/(maxes[index0] - mins[index0]); y = (y-mins[index1])/(maxes[index1] - mins[index1]); QPointF point(y*w + pad, x*h + pad); float radius = 5; Canvas::drawSample(painter, point, radius, labels[i]); } painter.setBrush(Qt::NoBrush); painter.setPen(Qt::black); painter.setRenderHint(QPainter::Antialiasing, false); painter.drawRect(pad/2,pad/2,w+pad, h+pad); painter.drawText(pad/2+1, map.height()-pad/2-1, QString("e%1 x e%2").arg(index1+1).arg(index0+1)); maps.push_back(map); } } if(bScroll) { pixmap = QPixmap((mapW+2*pad)*gridX, (mapH+2*pad)*gridY); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } else { pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height()); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } pixmap.fill(Qt::white); QPainter painter(&pixmap); FOR(i, maps.size()) { int xIndex = i%gridX; int yIndex = i/gridX; painter.drawPixmap(QPoint(xIndex*pixmap.width()/gridX, yIndex*pixmap.height()/gridY), maps[i]); } ui->display->setPixmap(pixmap); ui->display->repaint(); } void Expose::resizeEvent( QResizeEvent *event ) { if(ui->typeCombo->currentIndex() == 0 && ui->scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) { GenerateScatterPlot(true); } else Repaint(); repaint(); } void Expose::Repaint() { switch(ui->typeCombo->currentIndex()) { case 0: GenerateScatterPlot(); break; case 1: GenerateParallelCoords(); break; case 2: GenerateRadialGraph(); break; case 3: GenerateAndrewsPlots(); break; } repaint(); } void Expose::Clipboard() { QImage image = ui->display->pixmap()->toImage(); QClipboard *clipboard = QApplication::clipboard(); clipboard->setImage(image); } void Expose::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); if(!canvas) return; if(pixmap.isNull()) Repaint(); } mldemos-0.4.3/Core/expose.h000066400000000000000000000037251172143270300155310ustar00rootroot00000000000000#ifndef EXPOSE_H #define EXPOSE_H #include #include #include #include "ui_expose.h" namespace Ui { class Expose; } class Expose : public QWidget { Q_OBJECT public: explicit Expose(Canvas *canvas, QWidget *parent = 0); ~Expose(); static void DrawData(QPixmap& pixmap, std::vector samples, ivec labels, std::vector flags, int type, bool bProjected=false, QStringList names=QStringList(), std::pair bounds=std::make_pair(fvec(),fvec())); static void DrawData(QPixmap& pixmap, std::vector samples, std::vector sampleColors, std::vector flags, int type, bool bProjected=false, bool bLearned=false, QStringList names=QStringList(), std::pair bounds=std::make_pair(fvec(),fvec())); static void DrawTrajectories(QPixmap& pixmap, std::vector< std::vector > trajectories, ivec labels, int type, int drawMode, std::pair bounds=std::make_pair(fvec(),fvec())); static void DrawTrajectories(QPixmap& pixmap, std::vector< std::vector > trajectories, std::vector sampleColors, int type, int drawMode, std::pair bounds=std::make_pair(fvec(),fvec())); static void DrawVariableData(QPixmap& pixmap, std::vector samples, ivec labels, int type, fvec params, bool bProjected=false, QStringList names=QStringList()); static void DrawVariableData(QPixmap& pixmap, std::vector samples, std::vector sampleColors, int type, fvec params, bool bProjected=false, bool bLearned=false, QStringList names=QStringList()); protected: void paintEvent(QPaintEvent *event); void resizeEvent( QResizeEvent *event ); private: void GenerateScatterPlot(bool bCheckOnly=false); void GenerateParallelCoords(); void GenerateRadialGraph(); void GenerateAndrewsPlots(); private slots: void Clipboard(); void Repaint(); private: Ui::Expose *ui; Canvas *canvas; QPixmap pixmap; }; #endif // EXPOSE_H mldemos-0.4.3/Core/expose.ui000066400000000000000000000056611172143270300157200ustar00rootroot00000000000000 Expose 0 0 566 409 Form 0 0 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true 0 0 564 371 0 0 8 Scatterplot Matrix Parallel Coordinates Radial Graphs Andrews Plots To Clipboard Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter mldemos-0.4.3/Core/fileutils.cpp000077500000000000000000000007341172143270300165610ustar00rootroot00000000000000#include "fileutils.h" #include #include FileUtils::FileUtils(QString pathName) { path = QDir(pathName); } QStringList FileUtils::GetFiles(QString prefix, QString ext) { QStringList filters; filters << prefix+"*."+ext; QFileInfoList list = path.entryInfoList(filters); QStringList files; for(int i=0; i class FileUtils { QDir path; public: FileUtils(QString pathName); QStringList GetFiles(QString prefix, QString ext="avi"); }; #endif // FILEUTILS_H mldemos-0.4.3/Core/gettimeofday.cc000066400000000000000000000015411172143270300170370ustar00rootroot00000000000000#include "gettimeofday.h" int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag = 0; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; tmpres /= 10; /*convert into microseconds*/ /*converting file time to unix epoch*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } /* #define TEST #ifdef TEST int main() { struct timeval now; struct timezone tzone; gettimeofday(&now, NULL); gettimeofday(&now, &tzone); } #endif */ mldemos-0.4.3/Core/gettimeofday.h000066400000000000000000000026051172143270300167030ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _GETTIMEOFDAY_H_ #define _GETTIMEOFDAY_H_ #include #include #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz); #endif // _GETTIMEOFDAY_H_ mldemos-0.4.3/Core/interfaces.h000066400000000000000000000324161172143270300163500ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _INTERFACES_H_ #define _INTERFACES_H_ #include #include #include "classifier.h" #include "clusterer.h" #include "regressor.h" #include "dynamical.h" #include "maximize.h" #include "projector.h" #include "canvas.h" #include "drawTimer.h" #include #include #include #include #include #include #include class ClassifierInterface { public: // virtual functions to manage the algorithm creation virtual Classifier *GetClassifier() = 0; virtual void DrawModel(Canvas *canvas, QPainter &painter, Classifier *classifier) = 0; virtual void DrawInfo(Canvas *canvas, QPainter &painter, Classifier *classifier) = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Classifier *classifier) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; // drawing function void Draw(Canvas *canvas, Classifier *classifier) { if(!classifier || !canvas) return; canvas->liveTrajectory.clear(); int w = canvas->width(); int h = canvas->height(); { canvas->maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.model.setMask(bitmap); canvas->maps.model.fill(Qt::transparent); QPainter painter(&canvas->maps.model); DrawModel(canvas, painter, classifier); } { canvas->maps.info = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.info.setMask(bitmap); canvas->maps.info.fill(Qt::transparent); QPainter painter(&canvas->maps.info); DrawInfo(canvas, painter, classifier); } canvas->maps.confidence = QPixmap(); canvas->repaint(); } }; class ClustererInterface { public: // virtual functions to manage the algorithm creation virtual Clusterer *GetClusterer() = 0; virtual void DrawInfo(Canvas *canvas, QPainter &painter, Clusterer *clusterer) = 0; virtual void DrawModel(Canvas *canvas, QPainter &painter, Clusterer *clusterer) = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Clusterer *clusterer) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; void Draw(Canvas *canvas, Clusterer *clusterer) { if(!canvas || !clusterer) return; canvas->liveTrajectory.clear(); int w = canvas->width(); int h = canvas->height(); { QPixmap modelPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); modelPixmap.setMask(bitmap); modelPixmap.fill(Qt::transparent); QPainter painter(&modelPixmap); DrawModel(canvas, painter, clusterer); canvas->maps.model = modelPixmap; } { QPixmap infoPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); infoPixmap.setMask(bitmap); infoPixmap.fill(Qt::transparent); QPainter painter(&infoPixmap); DrawInfo(canvas, painter, clusterer); canvas->maps.info = infoPixmap; } canvas->repaint(); } }; class RegressorInterface { public: // virtual functions to manage the algorithm creation virtual Regressor *GetRegressor() = 0; virtual void DrawInfo(Canvas *canvas, QPainter &painter, Regressor *regressor) = 0; virtual void DrawModel(Canvas *canvas, QPainter &painter, Regressor *regressor) = 0; virtual void DrawConfidence(Canvas *canvas, Regressor *regressor) = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Regressor *regressor) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; void Draw(Canvas *canvas, Regressor *regressor) { if(!regressor || !canvas) return; canvas->liveTrajectory.clear(); int w = canvas->width(); int h = canvas->height(); { canvas->maps.confidence = QPixmap(w,h); canvas->maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.model.setMask(bitmap); canvas->maps.model.fill(Qt::transparent); QPainter painter(&canvas->maps.model); DrawModel(canvas, painter, regressor); } { QPixmap infoPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); infoPixmap.setMask(bitmap); infoPixmap.fill(Qt::transparent); QPainter painter(&infoPixmap); DrawInfo(canvas, painter, regressor); canvas->maps.info = infoPixmap; } DrawConfidence(canvas, regressor); canvas->repaint(); } }; class DynamicalInterface { public: // virtual functions to manage the algorithm creation virtual Dynamical *GetDynamical() = 0; virtual void DrawInfo(Canvas *canvas, QPainter &painter, Dynamical *dynamical) = 0; virtual void DrawModel(Canvas *canvas, QPainter &painter, Dynamical *dynamical) = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Dynamical *dynamical) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; virtual bool UsesDrawTimer() = 0; void Draw(Canvas *canvas, Dynamical *dynamical) { if(!dynamical || !canvas) return; int w = canvas->width(); int h = canvas->height(); canvas->maps.confidence = QPixmap(w,h); { canvas->maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.model.setMask(bitmap); canvas->maps.model.fill(Qt::transparent); QPainter painter(&canvas->maps.model); DrawModel(canvas, painter, dynamical); } { QPixmap infoPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); infoPixmap.setMask(bitmap); infoPixmap.fill(Qt::transparent); QPainter painter(&infoPixmap); DrawInfo(canvas, painter, dynamical); canvas->maps.info = infoPixmap; } canvas->repaint(); } }; class AvoidanceInterface { public: virtual ObstacleAvoidance *GetObstacleAvoidance() = 0; virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(ObstacleAvoidance *avoid) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; }; class MaximizeInterface { public: // virtual functions to manage the algorithm creation virtual Maximizer *GetMaximizer() = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Maximizer *maximizer) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; }; class ProjectorInterface { public: // virtual functions to manage the algorithm creation virtual Projector *GetProjector() = 0; virtual void DrawInfo(Canvas *canvas, QPainter &painter, Projector *projector) = 0; virtual void DrawModel(Canvas *canvas, QPainter &painter, Projector *projector) = 0; // virtual functions to manage the GUI and I/O virtual QString GetName() = 0; virtual QString GetAlgoString() = 0; virtual QString GetInfoFile() = 0; virtual QWidget *GetParameterWidget() = 0; virtual void SetParams(Projector *projector) = 0; virtual void SaveOptions(QSettings &settings) = 0; virtual bool LoadOptions(QSettings &settings) = 0; virtual void SaveParams(QTextStream &stream) = 0; virtual bool LoadParams(QString name, float value) = 0; void Draw(Canvas *canvas, Projector *projector) { if(!canvas || !projector) return; canvas->liveTrajectory.clear(); int w = canvas->width(); int h = canvas->height(); { QPixmap modelPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); modelPixmap.setMask(bitmap); modelPixmap.fill(Qt::transparent); QPainter painter(&modelPixmap); DrawModel(canvas, painter, projector); canvas->maps.model = modelPixmap; } { QPixmap infoPixmap(w, h); QBitmap bitmap(w,h); bitmap.clear(); infoPixmap.setMask(bitmap); infoPixmap.fill(Qt::transparent); QPainter painter(&infoPixmap); DrawInfo(canvas, painter, projector); canvas->maps.info = infoPixmap; } canvas->repaint(); } }; class CollectionInterface { protected: std::vector classifiers; std::vector clusterers; std::vector regressors; std::vector dynamicals; std::vector maximizers; std::vector projectors; public: virtual QString GetName() = 0; std::vector GetClassifiers() {return classifiers;} std::vector GetClusterers() {return clusterers;} std::vector GetRegressors() {return regressors;} std::vector GetDynamicals() {return dynamicals;} std::vector GetMaximizers() {return maximizers;} std::vector GetProjectors() {return projectors;} ~CollectionInterface() { FOR(i, classifiers.size()) if(classifiers[i]) delete classifiers[i]; FOR(i, clusterers.size()) if(clusterers[i]) delete clusterers[i]; FOR(i, regressors.size()) if(regressors[i]) delete regressors[i]; FOR(i, dynamicals.size()) if(dynamicals[i]) delete dynamicals[i]; FOR(i, maximizers.size()) if(maximizers[i]) delete maximizers[i]; FOR(i, projectors.size()) if(projectors[i]) delete projectors[i]; } }; class InputOutputInterface { public: // signatures for plugin slots and signals (SLOT() and SIGNAL() functions) virtual const char* QueryClassifierSignal() = 0; // void QueryClassifier(std::vector samples); virtual const char* QueryRegressorSignal() = 0; // void QueryRegressor(std::vector samples); virtual const char* QueryDynamicalSignal() = 0; // void QueryDynamical(std::vector samples); virtual const char* QueryClustererSignal() = 0; // void QueryClusterer(std::vector samples); virtual const char* QueryMaximizerSignal() = 0; // void QueryMaximizer(std::vector samples); virtual const char* SetDataSignal() = 0; // void SetData(std::vector samples, ivec labels, std::vector trajectories); virtual const char* SetTimeseriesSignal() = 0; // void SetTimeseriesSignal(std::vector series); virtual const char* FetchResultsSlot() = 0; // void FetchResults(std::vector results); virtual QObject *object() = 0; // trick to get access to the QObject interface for signals and slots virtual const char* DoneSignal() = 0; // void Done(QObject *); virtual QString GetName() = 0; virtual void Start() = 0; virtual void Stop() = 0; }; Q_DECLARE_INTERFACE(ClassifierInterface, "com.MLDemos.ClassifierInterface/1.0") Q_DECLARE_INTERFACE(ClustererInterface, "com.MLDemos.ClustererInterface/1.0") Q_DECLARE_INTERFACE(RegressorInterface, "com.MLDemos.RegressorInterface/1.0") Q_DECLARE_INTERFACE(DynamicalInterface, "com.MLDemos.DynamicalInterface/1.0") Q_DECLARE_INTERFACE(AvoidanceInterface, "com.MLDemos.AvoidInterface/1.0") Q_DECLARE_INTERFACE(MaximizeInterface, "com.MLDemos.MaximizeInterface/1.0") Q_DECLARE_INTERFACE(ProjectorInterface, "com.MLDemos.ProjectorInterface/1.0") Q_DECLARE_INTERFACE(CollectionInterface, "com.MLDemos.CollectionInterface/1.0") Q_DECLARE_INTERFACE(InputOutputInterface, "com.MLDemos.InputOutputInterface/1.0") #endif // _INTERFACES_H_ mldemos-0.4.3/Core/main.cpp000066400000000000000000000024041172143270300154760ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include #include //Q_IMPORT_PLUGIN(mld_classifySVM) int main(int argc, char *argv[]) { QApplication a(argc, argv); QString filename = ""; if(argc > 1) filename = QString(argv[1]); MLDemos w(filename); w.show(); return a.exec(); } mldemos-0.4.3/Core/maximize.h000066400000000000000000000050341172143270300160440ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _MAXIMIZE_H_ #define _MAXIMIZE_H_ #include #include "public.h" #include "mymaths.h" #include class Maximizer { protected: u32 dim; int w, h; bool bIterative; bool bConverged; fvec maximum; std::vector< fvec > visited; std::vector< fvec > history; std::vector historyValue; double maximumValue; float *data; int evaluations; public: int age, maxAge; double stopValue; Maximizer() : evaluations(0), stopValue(.99), maxAge(200), age(0), dim(2), bIterative(false) , bConverged(true), data(NULL), w(1), h(1), maximumValue(-FLT_MAX){ maximum.resize(2);}; ~Maximizer(){if(data) delete [] data;}; void Maximize(float *dataMap, int w, int h) {Train(dataMap,fVec(w,h));}; bool hasConverged(){return bConverged;}; void SetConverged(bool converged){bConverged = converged;}; std::vector &History(){return history;}; std::vector &HistoryValue(){return historyValue;}; fvec &Maximum(){return maximum;}; double MaximumValue(){return GetValue(maximum);}; std::vector &Visited(){return visited;}; int &Evaluations(){return evaluations;}; float GetValue(fvec sample) { int xIndex = max(0, min(w-1, (int)(sample[0]*w))); int yIndex = max(0, min(h-1, (int)(sample[1]*h))); int index = yIndex*w + xIndex; return data[index]; } virtual void Draw(QPainter &painter){}; virtual void Train(float *dataMap, fVec size, fvec startingPoint=fvec()){}; virtual fvec Test( const fvec &sample){ return fvec(); }; virtual fvec Test(const fVec &sample){ return Test((fvec)sample); }; virtual char *GetInfoString(){return NULL;}; }; #endif // _MAXIMIZE_H_ mldemos-0.4.3/Core/mymaths.cpp000066400000000000000000000116601172143270300162400ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "public.h" #include "mymaths.h" #ifdef WITHBOOST #include "spline.h" #endif /************************************************************************/ /* std::vector */ /************************************************************************/ void operator+= (fvec &a, const fvec b) { if(a.size() == 2) { a[0] += b[0]; a[1] += b[1]; } else { FOR(i, min(a.size(),b.size())) a[i] += b[i]; } } void operator-= (fvec &a, const fvec b) { if(a.size() == 2) { a[0] -= b[0]; a[1] -= b[1]; } else { FOR(i, min(a.size(), b.size())) a[i] -= b[i]; } } void operator+= (fvec &a, const float b) { if(a.size() == 2) { a[0] += b; a[1] += b; } else { FOR(i, a.size()) a[i] += b; } } void operator-= (fvec &a, const float b) { if(a.size() == 2) { a[0] -= b; a[1] -= b; } else { FOR(i, a.size()) a[i] -= b; } } void operator *= (fvec &a, const float b) { if(a.size() == 2) { a[0] *= b; a[1] *= b; } else { FOR(i, a.size()) a[i] *= b; } } void operator /= (fvec &a, const float b) { if(a.size() == 2) { a[0] /= b; a[1] /= b; } else { FOR(i, a.size()) a[i] /= b; } } /* fvec& operator << (fvec& a, const fvec b) { a.insert(a.end(), b.begin(), b.end()); return a; } fvec& operator << (fvec &a, const float b) { a.push_back(b); return a; } */ fvec operator + (const fvec a, const fvec b) { fvec c = a; FOR(i, min(a.size(), b.size())) c[i] += b[i]; return c; } fvec operator - (const fvec a, const fvec b) { fvec c = a; FOR(i, min(a.size(), b.size())) c[i] -= b[i]; return c; } fvec operator + (const fvec a, const float b) { fvec c = a; FOR(i, c.size()) c[i] += b; return c; } fvec operator - (const fvec a, const float b) { fvec c = a; FOR(i, c.size()) c[i] -= b; return c; } fvec operator * (const fvec a, const float b) { fvec c = a; FOR(i, c.size()) c[i] *= b; return c; } fvec operator / (const fvec a, const float b) { fvec c = a; FOR(i, c.size()) c[i] /= b; return c; } float operator * (const fvec a, const fvec b) { float sum = 0; FOR(i, min(a.size(), b.size())) sum += a[i] * b[i]; return sum; } bool operator == (const fvec a, const fvec b) { if(a.size() != a.size()) return false; FOR(i, a.size()) { if(a[i] != b[i]) return false; } return true; } bool operator == (const fvec a, const float b) { FOR(i, a.size()) if(a[i] != b) return false; return true; } bool operator != (const fvec a, const fvec b) { if(a.size() != a.size()) return true; FOR(i, a.size()) { if(a[i] != b[i]) return true; } return false; } bool operator != (const fvec a, const float b) { FOR(i, a.size()) if(a[i] != b) return true; return false; } std::vector interpolate(std::vector a, int count) { // basic interpolation std::vector res; res.resize(count); FOR(i, count) { int length = a.size(); float ratio = i/(float)count; int index = (int)(ratio*length); float remainder = ratio*length - (float)(int)(ratio*length); if(remainder == 0 || index == length-1) res[i] = a[index]; else // we need to interpolate { fvec pt0 = a[index]; fvec pt1 = a[index+1]; res[i] = pt0*(1.f-remainder) + pt1*remainder; } } return res; } std::vector interpolateSpline(std::vector a, int count) { #ifndef WITHBOOST return interpolate(a, count); // we take the easy way out #endif // basic interpolation std::vector res; res.resize(count); FOR(i, count) { int length = a.size(); float ratio = i/(float)count; int index = (int)(ratio*length); float remainder = ratio*length - (float)(int)(ratio*length); if(remainder == 0 || index == length-1) res[i] = a[index]; else // we need to interpolate { fvec pt0 = a[index]; fvec pt1 = a[index+1]; res[i] = pt0*(1.f-remainder) + pt1*remainder; } } return res; } mldemos-0.4.3/Core/mymaths.h000066400000000000000000000120201172143270300156740ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _MY_MATHS_H #define _MY_MATHS_H #include #include #include #include "types.h" struct fVec { friend std::ostream& operator<<(std::ostream& output, const fVec& v) { output << "(" << v.x << ", " << v.y <<")"; return output; // for multiple << operators. } friend std::istream & operator>>(std::istream &input, fVec &v) { input >> v.x >> v.y; return input; // for multiple >> operators. } fVec(const float x=0, const float y=0) : x(x),y(y){} fVec(const float* v) : x(v[0]),y(v[1]){} fVec(const fVec& v) : x(v.x),y(v.y){} fVec(fvec v) {x=v.size()>1?v[0]:0;x=v.size()>1?v[1]:0;} //fVec(const fvec &v) {x=v.size()>1?v[0]:0;x=v.size()>1?v[1]:0;} union { float _[2]; struct {float x,y;}; }; float& operator[] (unsigned int i){return _[i];} float& operator() (unsigned int i){return _[i];} fVec& operator= (const fVec &v) { if (this != &v) { x = v.x; y = v.y; } return *this; } operator fvec () const { fvec a; a.resize(2); a[0] = x; a[1] = y; return a; } //operators fVec operator-() const {return fVec(-x, -y);} fVec operator+(const fVec& v) const {return fVec(x + v.x, y + v.y);} fVec operator-(const fVec& v) const {return fVec(x - v.x, y - v.y);} float operator*(const fVec& v) const {return x*v.x + y*v.y;} fVec operator+(const float& v) const {return fVec(x + v, y + v);} fVec operator-(const float& v) const {return fVec(x - v, y - v);} fVec operator*(const float& d) const {return fVec(x * d, y * d);} fVec operator/(const float& d) const {return fVec(x / d, y / d);} bool operator==(const fVec& v) const {return x == v.x && y == v.y;} bool operator!=(const fVec& v) const {return x != v.x || y != v.y;} fVec& operator+=(const fVec& v) {x += v.x;y += v.y;return *this;} fVec& operator-=(const fVec& v) {x -= v.x;y -= v.y;return *this;} fVec& operator+=(const float& v) {x += v;y += v;return *this;} fVec& operator-=(const float& v) {x -= v;y -= v;return *this;} fVec& operator*=(const float& d) {x *= d;y *= d;return *this;} fVec& operator/=(const float& d) { if(d==0) {x = y = 0; return *this;} float inv = 1.f / d;x *= inv;y *= inv;return *this;} // other functions inline int size() const{return 2;} inline fVec& normalize() {if(x==0 && y==0){x=1;return *this;};float l = length();x /= l;y /= l;return *this;} inline float lengthSquared() const {return x * x + y * y;} inline float length() const {return sqrt(lengthSquared());} }; void operator += (fvec &a, const fvec b); void operator -= (fvec &a, const fvec b); void operator += (fvec &a, const float b); void operator -= (fvec &a, const float b); void operator *= (fvec &a, const float b); void operator /= (fvec &a, const float b); //fvec& operator << (fvec &a, const fvec b); //fvec& operator << (fvec &a, const float b); fvec operator + (const fvec a, const fvec b); fvec operator - (const fvec a, const fvec b); fvec operator + (const fvec a, const float b); fvec operator - (const fvec a, const float b); fvec operator * (const fvec a, const float b); fvec operator / (const fvec a, const float b); float operator * (const fvec a, const fvec b); bool operator == (const fvec a, const fvec b); bool operator == (const fvec a, const float b); bool operator != (const fvec a, const fvec b); bool operator != (const fvec a, const float b); std::vector interpolate(std::vector a, int count); std::vector interpolateSpline(std::vector a, int count); // generate random sample from normal distribution static inline float ranf() { return rand()/(float)RAND_MAX; } static inline float RandN(float mean=0.f, float sigma=1.f) { float x1, x2, w, y1, y2; do { x1 = 2.0 * ranf() - 1.0; x2 = 2.0 * ranf() - 1.0; w = x1 * x1 + x2 * x2; } while ( w >= 1.0 ); w = sqrt( (-2.0 * log( w ) ) / w ); y1 = x1 * w; //y2 = x2 * w; return y1*sigma + mean; } static inline fvec RandN(int dim, float mean=0.f, float sigma=1.f) { if(!dim) return fvec(); fvec res; res.resize(dim); FOR(d,dim) res[d] = RandN(mean, sigma); return res; } #endif // _MY_MATHS_H mldemos-0.4.3/Core/obstacles.h000066400000000000000000000027061172143270300162030ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _OBSTACLES_H_ #define _OBSTACLES_H_ #include #include "datasetManager.h" #include class ObstacleAvoidance { public: std::vector< Obstacle > obstacles; virtual void SetObstacles(std::vector< Obstacle > obstacles) { this->obstacles = obstacles; } virtual fvec Avoid(fvec &x, fvec &xdot) { fvec newXDot; newXDot.resize(2); newXDot = xdot; return newXDot; }; virtual fVec Avoid(fVec &x, fVec &xdot) { fvec vx=x, vxdot=xdot; return fVec(Avoid(vx, vxdot)); } }; #endif // _OBSTACLES_H_ mldemos-0.4.3/Core/optimization_test_functions.h000066400000000000000000000253101172143270300220750ustar00rootroot00000000000000 /* //---------------- Author: Francesco Castellini* and Annalisa Riccardi** ---------------// //------- Affiliation: -----------------------------------------------------------------// //--------------* Dipartimento di Ingegneria Aerospaziale, Politecnico di Milano -------// //--------------**Centrum for Industrial Mathematics, University of Bremen -------------// //--------E-mail: castellfr@gmail.com, nina1983@gmail.com ------------------------------// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include using namespace Eigen; using namespace std; static const double Pi() {return 3.14159265358979323846; }; //SINGLE OBJECTIVE OPTIMIZATION PROBLEMS (see http://www.geatbx.com/docu/fcnindex-01.html#P129_5426 for mathematical definition) // Ackley's Path function // f10(x)=-a·exp(-b·sqrt(1/n·sum(x(i)^2)))-exp(1/n·sum(cos(c·x(i))))+a+exp(1) // a=20; b=0.2; c=2·pi; i=1:n; -32.768<=x(i)<=32.768. Eigen::VectorXd ackley(Eigen::VectorXd& x) { Eigen::VectorXd y(1); double a=20, b=0.2, c=2*Pi(); int nvars = x.size(); double sumX = 0; for(int i=0; i 11 vars //Parameters(fixed): n1 bits for x1, n2 bits for x2,...x11 { Eigen::VectorXd y(2); Eigen::VectorXd X(x.size()); double g, h; int i, j, n, n1, n2; g=0; n=11; n1=30; n2=5; int *u = new int[n]; for(i=0; i #include #include "parser.h" /* CSVRow stuff */ std::istream& operator>>(std::istream& str,CSVRow& data) { data.readNextRow(str); return str; } std::string const& CSVRow::operator[](std::size_t index) const { return m_data[index]; } std::string CSVRow::at(size_t column) const { return m_data.at(column); } std::string CSVRow::getFirstCell() const { if(!m_data.size()) return string(); return m_data.at(0); } std::string CSVRow::getLastCell() const { if(!m_data.size()) return string(); return m_data.back(); } std::vector CSVRow::getParsedLine() const { return m_data; } std::size_t CSVRow::size() const { return m_data.size(); } void CSVRow::readNextRow(std::istream& str) { // read line from file std::string line; std::getline(str,line); // we try using commas, semi-colons and tabs // convert to stream std::stringstream lineStream(line); std::string cell; // update row (array) content m_data.clear(); while(std::getline(lineStream,cell,separator[0])) { std::string test = cell; std::remove(test.begin(), test.end(), ' '); if(test.empty()) continue; m_data.push_back(cell); } } unsigned int getType(string input) { if (is(input)) return UNSIGNED_INT_TYPE; if (is(input)) return INT_TYPE; if (is(input)) return FLOAT_TYPE; if (is(input)) return CHAR_TYPE; if (is(input)) return STRING_TYPE; return UNKNOWN_TYPE; } /* CSVIterator stuff */ CSVIterator::CSVIterator(std::istream& str, std::string separator) : m_str(str.good()?&str:NULL), separator(separator), m_row(separator) { ++(*this); } CSVIterator::CSVIterator():m_str(NULL) { } bool CSVIterator::eof() { return (m_str == NULL); } // Pre Increment CSVIterator& CSVIterator::operator++() { if (m_str) { (*m_str) >> m_row; m_str = m_str->good()?m_str:NULL; } return *this; } // Post increment CSVIterator CSVIterator::operator++(int) { CSVIterator tmp(*this); ++(*this); return tmp; } CSVRow const& CSVIterator::operator*() const { return m_row; } CSVRow const* CSVIterator::operator->() const { return &m_row; } bool CSVIterator::operator!=(CSVIterator const& rhs) { return !((*this) == rhs); } bool CSVIterator::operator==(CSVIterator const& rhs) { return ((this == &rhs) || ((this->m_str == NULL) && (rhs.m_str == NULL))); } /* CSVParser stuff */ CSVParser::CSVParser() { bFirstRowAsHeader = false; outputLabelColumn = 2; } void CSVParser::clear() { outputLabelColumn = 0; classLabels.clear(); data.clear(); dataTypes.clear(); } void CSVParser::parse(const char* fileName) { // init file.open(fileName); if(!file.is_open()) return; std::string separators[] = {",", ";", "\t", " "}; int separatorCount = 4; int bestSeparator = 0; int dim=0; // we test the separators to find which one is best for(int i=0; isize()) continue; vector parsed = parser->getParsedLine(); //qDebug() << "separator: " << separators[i].c_str() << ":" << parsed.size(); if(parsed.size() > dim) { dim = parsed.size(); bestSeparator = i; } } file.seekg(0); data.clear(); for(CSVIterator parser(file, separators[bestSeparator]);!parser.eof(); ++parser) { if(!parser->size()) continue; vector parsed = parser->getParsedLine(); if(!parsed.size()) continue; // Fill dataset data.push_back(parsed); } cout << "Parsing done, read " << data.size() << " entries" << endl; cout << "Found " << data.at(0).size()-1 << " input labels" << endl; // look for data types for(size_t i = 0; i < data.at(1).size(); i++) { // Look for a non-empty cell // start with 2nd row as first might be input labels size_t testRow = 1; while(data.at(testRow).at(i) == "?") testRow++; // The whole column is missing data... if (testRow == data.size()) { cout << "WebImport: Warning: Found empty column" << endl; // TODO delete it } // save input types dataTypes.push_back(getType(data.at(testRow).at(i))); } // Read output (class) labels getOutputLabelTypes(true); file.close(); } void CSVParser::setOutputColumn(int column) { outputLabelColumn = column; //getOutputLabelTypes(true); // need to update output label types } map CSVParser::getOutputLabelTypes(bool reparse) { if (!reparse) return classLabels; unsigned int id = 0; pair::iterator,bool> ret; // Use by default the last column as output class if ((data.size() && outputLabelColumn == -1) || outputLabelColumn >= data.size()) outputLabelColumn = data.at(0).size()-1; for(vector >::iterator it = data.begin(); it(it->at(outputLabelColumn),id) ); if (ret.second == true) id++; // new class found } return classLabels; } vector CSVParser::getMissingValIndex() { vector missingValIndex; size_t nbCols = data.at(0).size(); for (size_t i = 0; i < data.size(); i++) for (size_t j = 0; j < nbCols; j++) if (data[i][j] == "?") missingValIndex.push_back(i); return missingValIndex; } bool CSVParser::hasData() { return data.size(); } void CSVParser::cleanData(unsigned int acceptedTypes) { vector::iterator it_str; vector::iterator it_uint = dataTypes.begin(); for(size_t i = 0; i < dataTypes.size(); i++) if (!(dataTypes[i]&acceptedTypes) && // data type does not correspond to a requested one (i != outputLabelColumn)) // output labels are stored separately, ignore { cout << "Removing colum " << i << " of type " << dataTypes[i] << " ... "; for(size_t j = 0; j < data.size(); j++) { /* @note it seems that if we have --i instead of (i-1), the compiler produces bad code (SIGSEGV) */ it_str = data.at(j).begin() + (i-1); data.at(j).erase(it_str); // delete the column } cout << "and matching type reference ... " ; it_uint = dataTypes.begin() + (i-1); dataTypes.erase(it_uint); // delete the input to stay consistant i--; if (i < outputLabelColumn) outputLabelColumn--; } } pair,ivec> CSVParser::getData(ivec excludeIndex, int maxSamples) { int count = data.size(); if(bFirstRowAsHeader) count--; int headerSkip = bFirstRowAsHeader?1:0; if(count <= 0) return pair,ivec>(); vector samples(count); ivec labels(count); int dim = data[0].size(); if(outputLabelColumn != -1) outputLabelColumn = min(dim-1, outputLabelColumn); vector< map > labelMaps(dim); ivec labelCounters(dim,0); pair::iterator,bool> ret; FOR(i, data.size()) { if(!i && bFirstRowAsHeader) continue; // check if it's always a number fvec& sample = samples[i-headerSkip]; sample.resize((outputLabelColumn==-1) ? dim : dim-1); FOR(j, dim) { QString s(data[i][j].c_str()); bool ok; float val = s.toFloat(&ok); if(j==outputLabelColumn || !ok) { if(labelMaps[j].count(data[i][j]) > 0) val = labelMaps[j][data[i][j]]; else { val = (float)labelCounters[j]; ret = labelMaps[j].insert(pair(data[i][j], val)); if(ret.second) labelCounters[j]++; } } if(j!=outputLabelColumn) { if(outputLabelColumn==-1) sample[j] = val; else { int index = j < outputLabelColumn ? j : j-1; sample[index] = val; } } } } if(outputLabelColumn == -1) { FOR(i, data.size()) { if(!i && bFirstRowAsHeader) continue; labels[i-headerSkip] = 0; } } else { /* qDebug() << "label indices"; for(map::iterator it = labelMaps[outputLabelColumn].begin(); it != labelMaps[outputLabelColumn].end(); it++) { qDebug() << (it->first).c_str() << " " << it->second; } */ bool numerical = true; FOR(i, data.size()) { if(!i && bFirstRowAsHeader) continue; bool ok; float val = QString(data[i][outputLabelColumn].c_str()).toFloat(&ok); if(!ok) { numerical = false; break; } } FOR(i, data.size()) { if(!i && bFirstRowAsHeader) continue; bool ok; float val = QString(data[i][outputLabelColumn].c_str()).toFloat(&ok); if(numerical) { labels[i-headerSkip] = val; } else { int label = labelMaps[outputLabelColumn][data[i][outputLabelColumn]]; labels[i-headerSkip] = label; } } } if(maxSamples != -1 && maxSamples < samples.size()) { vector newSamples(maxSamples); ivec newLabels(maxSamples); u32 *perm = randPerm(maxSamples); FOR(i, maxSamples) { newSamples[i] = samples[perm[i]]; newLabels[i] = labels[perm[i]]; } samples = newSamples; labels = newLabels; count = samples.size(); delete [] perm; } if(!excludeIndex.size()) return pair,ivec>(samples,labels); vector newSamples(count); int newDim = dim - excludeIndex.size(); if(outputLabelColumn != -1) newDim--; //qDebug() << "Indices to be excluded: " << excludeIndex.size() << "(newDim: " << newDim << ")"; FOR(i, excludeIndex.size()) { //qDebug() << i << ":" << excludeIndex[i]; // if it's the output we can ignore it but we need to reincrement the number of dimensions if(excludeIndex[i] == outputLabelColumn) { newDim++; break; } } vector bExclude(dim, false); FOR(i, excludeIndex.size()) { bExclude[excludeIndex[i]] = true; } FOR(i, samples.size()) { newSamples[i].resize(newDim); int nD = 0; FOR(d, dim) { if(bExclude[d] || d == outputLabelColumn) continue; if(outputLabelColumn == -1) newSamples[i][nD] = samples[i][d]; else if (d < outputLabelColumn) newSamples[i][nD] = samples[i][d]; else if(d > outputLabelColumn) newSamples[i][nD] = samples[i][d-1]; nD++; } } qDebug() << "Imported samples: " << newSamples.size() << " labels: " << labels.size(); return pair,ivec>(newSamples,labels); } mldemos-0.4.3/Core/parser.h000066400000000000000000000073501172143270300155200ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2011 Chrstophe Paccolat Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef PARSER_H #define PARSER_H #define UNSIGNED_INT_TYPE 1 #define INT_TYPE 2 #define FLOAT_TYPE 4 #define DOUBLE_TYPE 8 #define CHAR_TYPE 16 #define STRING_TYPE 32 #define UNKNOWN_TYPE 64 #define ALL_TYPES 127 #define NUMERIC_TYPES (UNSIGNED_INT_TYPE | INT_TYPE | FLOAT_TYPE | DOUBLE_TYPE) #define MISSING_VALUE "?" #include #include #include #include #include #include #include #include using namespace std; template bool is(const std::string &s) { std::istringstream stream(s); T instance; return ((stream >> instance) && (stream >> std::ws) && stream.eof()); } class CSVRow { public: CSVRow(std::string separator = ","):separator(separator){} std::string const& operator[](std::size_t index) const; std::string at(size_t column) const; std::string getFirstCell() const; std::string getLastCell() const; std::vector getParsedLine() const; std::size_t size() const; void readNextRow(std::istream& str); private: std::vector m_data; string separator; }; class CSVIterator { public: typedef std::input_iterator_tag iterator_category; typedef CSVRow value_type; typedef std::size_t difference_type; typedef CSVRow* pointer; typedef CSVRow& reference; CSVIterator(std::istream& str, std::string separator=","); CSVIterator(); bool eof(); // Pre Increment CSVIterator& operator++(); // Post increment CSVIterator operator++(int); CSVRow const& operator*() const; CSVRow const* operator->() const; bool operator!=(CSVIterator const& rhs); bool operator==(CSVIterator const& rhs); private: std::string separator; std::istream* m_str; CSVRow m_row; }; class CSVParser { public: CSVParser(); void clear(); void parse(const char* fileName); vector getMissingValIndex(); void cleanData(unsigned int acceptedTypes); pair,ivec> getData(ivec excludeIndex = ivec(), int maxSamples=-1); map getOutputLabelTypes(bool reparse); void setOutputColumn(int column); void setFirstRowAsHeader(bool value){bFirstRowAsHeader = value;} bool hasData(); vector getDataType(){return dataTypes;} int getCount(){return data.size();} vector< vector > getRawData(){return data;} static pair, ivec> numericFromRawData(vector< vector > rawData); private: bool bFirstRowAsHeader; int outputLabelColumn; ifstream file; map classLabels; vector > data; vector dataTypes; }; #endif // PARSER_H mldemos-0.4.3/Core/projector.h000066400000000000000000000012011172143270300162200ustar00rootroot00000000000000#ifndef PROJECTOR_H #define PROJECTOR_H #include #include "mymaths.h" class Projector { public: std::vector projected; std::vector source; u32 dim; u32 startIndex, stopIndex; Projector() : dim(2), startIndex(0), stopIndex(-1) {} ~Projector(){} virtual void Train(std::vector< fvec > samples, ivec labels){} virtual fvec Project(const fvec &sample){ return sample; } virtual fvec Project(const fVec &sample){ return Project((fvec)sample); } virtual char *GetInfoString(){return NULL;} virtual std::vector GetProjected(){ return projected; } }; #endif // PROJECTOR_H mldemos-0.4.3/Core/public.h000066400000000000000000000041611172143270300154770ustar00rootroot00000000000000/* Public inclusions for opencv Copyright (C) 2007 basilio noris This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /*! * \file public.h * \author Basilio Noris * \date 25-11-06 * Public includes for opencv and types definitions */ #ifndef _PUBLIC_H_ #define _PUBLIC_H_ #ifdef MSVC #pragma warning(disable:4996) // avoids the sprintf_s and fopen_s warning which dont exist on linux ;) #pragma warning(disable:4244) // conversion from X to Y, possible loss of data #pragma warning(disable:4305) // 'initializing' : truncation from X to Y #endif #include #include #include #include #include // types and macros #include "types.h" // opencv includes /* #include #include #include #include #include #include #include */ #include static const QColor SampleColor [22]= { QColor(255,255,255), QColor(255,0,0), QColor(0,255,0), QColor(0,0,255), QColor(255,255,0), QColor(255,0,255), QColor(0,255,255), QColor(255,128,0), QColor(255,0,128), QColor(0,255,128), QColor(128,255,0), QColor(128,0,255), QColor(0,128,255), QColor(128,128,128), QColor(80,80,80), QColor(0,128,80), QColor(255,80,0), QColor(255,0,80), QColor(0,255,80), QColor(80,255,0), QColor(80,0,255), QColor(0,80,255) }; static const int SampleColorCnt = 22; #endif //_PUBLIC_H_ mldemos-0.4.3/Core/regressor.h000066400000000000000000000041751172143270300162410ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _REGRESSOR_H_ #define _REGRESSOR_H_ #include #include "mymaths.h" extern "C" enum {REGR_SVR, REGR_RVM, REGR_GMR, REGR_GPR, REGR_KNN, REGR_MLP, REGR_LINEAR, REGR_LWPR, REGR_KRLS, REGR_NONE} regressorType; class Regressor { protected: std::vector< fvec > samples; ivec classes; ivec labels; std::vector< fvec >testSamples; ivec testClasses; ivec testLabels; u32 dim; u32 posClass; f32 classThresh; f32 classSpan; s32 class2labels[255]; ivec labels2class; bool bFixedThreshold; public: std::vector crossval; fvec fmeasures; fvec trainErrors, testErrors; int type; int outputDim; Regressor() : posClass(0), bFixedThreshold(true), classThresh(0.5f), classSpan(0.1f), outputDim(-1), type(REGR_NONE){} std::vector GetSamples(){return samples;} void SetOutputDim(int outputDim){this->outputDim = outputDim;} virtual void Train(std::vector< fvec > samples, ivec labels){} virtual fvec Test( const fvec &sample){ return fvec(); } virtual fVec Test(const fVec &sample){ if (dim==2) return fVec(Test((fvec)sample)); fvec s = (fvec)sample; s.resize(dim,0); return Test(s);} virtual char *GetInfoString(){return NULL;} }; #endif // _REGRESSOR_H_ mldemos-0.4.3/Core/roc.cpp000066400000000000000000000165251172143270300153460ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "public.h" #include "basicMath.h" #include "mymaths.h" #include #include #include #include #include #include "roc.h" #define RES 512 #define PAD 16 std::vector > > rocCallBackAllData; std::vector > rocCallBackData; u32 rocIndex = 0; /* CvFont *rocfont; IplImage *roc = cvCreateImage(cvSize(RES,RES),8,3); IplImage *rocBackup = cvCloneImage(roc); */ bool UDLesser(f32pair e1, f32pair e2) { return e1.first < e2.first; } std::vector GetBestFMeasures() { std::vector fmeasures; FOR(i, rocCallBackAllData.size()) { float fmax = 0; FOR(j, rocCallBackAllData[i].size()) { if(rocCallBackAllData[i][j].size() <4) continue; if(rocCallBackAllData[i][j][3] > fmax) { fmax = rocCallBackAllData[i][j][3]; } } fmeasures.push_back(fmax); } return fmeasures; } void SaveRoc(std::vector data, const char *filename) { std::sort(data.begin(), data.end(), UDLesser); std::fstream file(filename, std::ios::out|std::ios::binary); u32 size = data.size(); file.write(reinterpret_cast(&size), sizeof(u32)); FOR(i, data.size()) { file.write(reinterpret_cast(&data[i]), sizeof(f32pair)); } file.close(); } std::vector LoadRoc(const char *filename) { std::vector data; std::fstream file(filename, std::ios::in|std::ios::binary); u32 size; file.read(reinterpret_cast(&size), sizeof(u32)); FOR(i, size) { f32pair pair; file.read(reinterpret_cast(&pair), sizeof(f32pair)); data.push_back(pair); } file.close(); return data; } // fixrocdata takes as input binary roc data and decides whether the two classes should be swapped // this should be done when the binary classifier is performing worse than random std::vector FixRocData(std::vector data) { if(!data.size()) return data; std::vector invData = data; int rocType = 0; // -1 or 1 FOR(i, data.size()) { if(data[i].second != 1 && data[i].second != -1) { rocType = 1; // 0 1 2 ... break; } } if(rocType == 0) { FOR(i, data.size()) invData[i].second = -invData[i].second; } else { FOR(i, data.size()) invData[i].second = 1 - invData[i].second; } float fData = GetBestFMeasure(data)[0]; float fInvData = GetBestFMeasure(invData)[0]; return (fData >= fInvData) ? data : invData; } float GetBestThreshold( std::vector data ) { if(!data.size()) return 0; std::vector< std::vector > measures; std::sort(data.begin(), data.end(), UDLesser); fVec oldVal(1,0); FOR(i, data.size()) { float thresh = data[i].first; u32 tp = 0, fp = 0; u32 fn = 0, tn = 0; FOR(j, data.size()) { if(data[j].second == 1) { if(data[j].first >= thresh) tp++; else fn++; } else { if(data[j].first >= thresh) fp++; else tn++; } } fVec val(fp/float(fp+tn), 1 - tp/float(tp+fn)); float precision = tp / float(tp+fp); float recall = tp /float(tp+fn); float fmeasure = tp == 0 ? 0 : 2 * (precision * recall) / (precision + recall); std::vector dat; dat.push_back(val.x); dat.push_back(val.y); dat.push_back(thresh); dat.push_back(fmeasure); measures.push_back(dat); oldVal = val; } float tmax = 0; float fmax = 0; FOR(j, measures.size()) { if(measures[j][3] > fmax) { tmax = measures[j][2]; fmax = measures[j][3]; } } return tmax; } fvec GetBestFMeasure( std::vector data ) { if(!data.size()) return fvec(1,0); std::vector< std::vector > measures; std::sort(data.begin(), data.end(), UDLesser); fVec oldVal(1,0); FOR(i, data.size()) { float thresh = data[i].first; u32 tp = 0, fp = 0; u32 fn = 0, tn = 0; FOR(j, data.size()) { if(data[j].second == 1) { if(data[j].first >= thresh) tp++; else fn++; } else { if(data[j].first >= thresh) fp++; else tn++; } } fVec val(fp/float(fp+tn), 1 - tp/float(tp+fn)); float precision = tp / float(tp+fp); float recall = tp /float(tp+fn); float fmeasure = tp == 0 ? 0 : 2 * (precision * recall) / (precision + recall); std::vector dat; dat.push_back(val.x); dat.push_back(val.y); dat.push_back(thresh); dat.push_back(fmeasure); dat.push_back(precision); dat.push_back(recall); measures.push_back(dat); oldVal = val; } float tmax = 0; float fmax = 0; float pmax = 0; float rmax = 0; FOR(j, measures.size()) { if(measures[j][3] > fmax) { tmax = measures[j][2]; fmax = measures[j][3]; pmax = measures[j][4]; rmax = measures[j][5]; } } fvec res(3); res[0] = fmax; res[1] = pmax; res[2] = rmax; return res; } float GetAveragePrecision( std::vector data ) { if(!data.size()) return 0; std::vector< std::vector > measures; std::sort(data.begin(), data.end(), UDLesser); float averagePrecision = 0, oldRecall = 1; float m = 0; FOR(i, data.size()) m += data[i].second; FOR(i, data.size()) { float thresh = data[i].first; u32 tp = 0, fp = 0; u32 fn = 0, tn = 0; FOR(j, data.size()) { if(data[j].second == 1) { if(data[j].first >= thresh) tp++; else fn++; } else { if(data[j].first >= thresh) fp++; else tn++; } } float t = float(tp+fp); float precision = tp / float(tp+fp); float recall = tp / float(tp+fn); //averagePrecision += precision/t; averagePrecision += precision*(oldRecall-recall); oldRecall = recall; } // averagePrecision /= m return averagePrecision; } float GetRocValueAt(std::vector data, float threshold) { if(!data.size()) return 0; u32 tp = 0, fp = 0; u32 fn = 0, tn = 0; FOR(j, data.size()) { if(data[j].second == 1) { if(data[j].first >= threshold) tp++; else fn++; } else { if(data[j].first >= threshold) fp++; else tn++; } } fVec val(fp/float(fp+tn), 1 - tp/float(tp+fn)); float precision = tp / float(tp+fp); float recall = tp /float(tp+fn); float fmeasure = tp == 0 ? 0 : 2 * (precision * recall) / (precision + recall); return fmeasure; } mldemos-0.4.3/Core/roc.h000066400000000000000000000036571172143270300150150ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef _ROC_H_ #define _ROC_H_ typedef std::pair f32pair; typedef std::vector rocData; /* IplImage *GetRocImage(); void roc_on_mouse( int event, int x, int y, int flags, void* param ); IplImage *RocImage(std::vector > dataVector, std::vector legend = std::vector(), CvSize res = cvSize(512,512)); void RocCurve(std::vector data); void RocCurves(std::vector > dataVector, std::vector legend = std::vector()); void SaveRocImage(const char *filename); */ void SaveRoc(std::vector data, const char *filename); std::vector LoadRoc(const char *filename); std::vector FixRocData(std::vector data); std::vector GetBestFMeasures(); float GetBestThreshold(std::vector data); std::vector GetBestFMeasure(std::vector data); float GetAveragePrecision(std::vector data); float GetRocValueAt(std::vector data, float threshold); #endif // _ROC_H_ mldemos-0.4.3/Core/spline.h000066400000000000000000000177421172143270300155240ustar00rootroot00000000000000#ifndef SPLINE_H #define SPLINE_H #ifdef WITHBOOST /* dynamo:- Event driven molecular dynamics simulator http://www.marcusbannerman.co.uk/dynamo Copyright (C) 2011 Marcus N Campbell Bannerman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include namespace ublas = boost::numeric::ublas; namespace magnet { namespace math { class Spline : private std::vector > { public: //The boundary conditions available enum BC_type {FIXED_1ST_DERIV_BC, FIXED_2ND_DERIV_BC, PARABOLIC_RUNOUT_BC}; //Constructor takes the boundary conditions as arguments, this //sets the first derivative (gradient) at the lower and upper //end points Spline(): _valid(false), _BCLow(FIXED_2ND_DERIV_BC), _BCHigh(FIXED_2ND_DERIV_BC), _BCLowVal(0), _BCHighVal(0) {} typedef std::vector > base; typedef base::const_iterator const_iterator; //Standard STL read-only container stuff const_iterator begin() const { return base::begin(); } const_iterator end() const { return base::end(); } void clear() { _valid = false; base::clear(); _data.clear(); } size_t size() const { return base::size(); } size_t max_size() const { return base::max_size(); } size_t capacity() const { return base::capacity(); } bool empty() const { return base::empty(); } //Add a point to the spline, and invalidate it so its //recalculated on the next access inline void addPoint(double x, double y) { _valid = false; base::push_back(std::pair(x,y)); } //Reset the boundary conditions inline void setLowBC(BC_type BC, double val = 0) { _BCLow = BC; _BCLowVal = val; _valid = false; } inline void setHighBC(BC_type BC, double val = 0) { _BCHigh = BC; _BCHighVal = val; _valid = false; } //Check if the spline has been calculated, then generate the //spline interpolated value double operator()(double xval) { if (!_valid) generate(); //Special cases when we're outside the range of the spline points if (xval <= x(0)) return lowCalc(xval); if (xval >= x(size()-1)) return highCalc(xval); //Check all intervals except the last one for (std::vector::const_iterator iPtr = _data.begin(); iPtr != _data.end()-1; ++iPtr) if ((xval >= iPtr->x) && (xval <= (iPtr+1)->x)) return splineCalc(iPtr, xval); return splineCalc(_data.end() - 1, xval); } private: ///////PRIVATE DATA MEMBERS struct SplineData { double x,a,b,c,d; }; //vector of calculated spline data std::vector _data; //Second derivative at each point ublas::vector _ddy; //Tracks whether the spline parameters have been calculated for //the current set of points bool _valid; //The boundary conditions BC_type _BCLow, _BCHigh; //The values of the boundary conditions double _BCLowVal, _BCHighVal; ///////PRIVATE FUNCTIONS //Function to calculate the value of a given spline at a point xval inline double splineCalc(std::vector::const_iterator i, double xval) { const double lx = xval - i->x; return ((i->a * lx + i->b) * lx + i->c) * lx + i->d; } inline double lowCalc(double xval) { const double lx = xval - x(0); const double firstDeriv = (y(1) - y(0)) / h(0) - 2 * h(0) * (_data[0].b + 2 * _data[1].b) / 6; switch(_BCLow) { case FIXED_1ST_DERIV_BC: return lx * _BCLowVal + y(0); case FIXED_2ND_DERIV_BC: return lx * lx * _BCLowVal + firstDeriv * lx + y(0); case PARABOLIC_RUNOUT_BC: return lx * lx * _ddy[0] + lx * firstDeriv + y(0); } throw std::runtime_error("Unknown BC"); } inline double highCalc(double xval) { const double lx = xval - x(size() - 1); const double firstDeriv = 2 * h(size() - 2) * (_ddy[size() - 2] + 2 * _ddy[size() - 1]) / 6 + (y(size() - 1) - y(size() - 2)) / h(size() - 2); switch(_BCHigh) { case FIXED_1ST_DERIV_BC: return lx * _BCHighVal + y(size() - 1); case FIXED_2ND_DERIV_BC: return lx * lx * _BCHighVal + firstDeriv * lx + y(size() - 1); case PARABOLIC_RUNOUT_BC: return lx * lx * _ddy[size()-1] + lx * firstDeriv + y(size() - 1); } throw std::runtime_error("Unknown BC"); } //These just provide access to the point data in a clean way inline double x(size_t i) const { return operator[](i).first; } inline double y(size_t i) const { return operator[](i).second; } inline double h(size_t i) const { return x(i+1) - x(i); } //Invert a arbitrary matrix using the boost ublas library template bool InvertMatrix(ublas::matrix A, ublas::matrix& inverse) { using namespace ublas; // create a permutation matrix for the LU-factorization permutation_matrix pm(A.size1()); // perform LU-factorization int res = lu_factorize(A,pm); if( res != 0 ) return false; // create identity matrix of "inverse" inverse.assign(ublas::identity_matrix(A.size1())); // backsubstitute to get the inverse lu_substitute(A, pm, inverse); return true; } //This function will recalculate the spline parameters and store //them in _data, ready for spline interpolation void generate() { if (size() < 2) throw std::runtime_error("Spline requires at least 2 points"); //If any spline points are at the same x location, we have to //just slightly seperate them { bool testPassed(false); while (!testPassed) { testPassed = true; std::sort(base::begin(), base::end()); for (base::iterator iPtr = base::begin(); iPtr != base::end() - 1; ++iPtr) if (iPtr->first == (iPtr+1)->first) { if ((iPtr+1)->first != 0) (iPtr+1)->first += (iPtr+1)->first * std::numeric_limits::epsilon() * 10; else (iPtr+1)->first = std::numeric_limits::epsilon() * 10; testPassed = false; break; } } } const size_t e = size() - 1; ublas::matrix A(size(), size()); for (size_t yv(0); yv <= e; ++yv) for (size_t xv(0); xv <= e; ++xv) A(xv,yv) = 0; for (size_t i(1); i < e; ++i) { A(i-1,i) = h(i-1); A(i,i) = 2 * (h(i-1) + h(i)); A(i+1,i) = h(i); } ublas::vector C(size()); for (size_t xv(0); xv <= e; ++xv) C(xv) = 0; for (size_t i(1); i < e; ++i) C(i) = 6 * ((y(i+1) - y(i)) / h(i) - (y(i) - y(i-1)) / h(i-1)); //Boundary conditions switch(_BCLow) { case FIXED_1ST_DERIV_BC: C(0) = 6 * ((y(1) - y(0)) / h(0) - _BCLowVal); A(0,0) = 2 * h(0); A(1,0) = h(0); break; case FIXED_2ND_DERIV_BC: C(0) = _BCLowVal; A(0,0) = 1; break; case PARABOLIC_RUNOUT_BC: C(0) = 0; A(0,0) = 1; A(1,0) = -1; break; } switch(_BCHigh) { case FIXED_1ST_DERIV_BC: C(e) = 6 * (_BCHighVal - (y(e) - y(e-1)) / h(e-1)); A(e,e) = 2 * h(e - 1); A(e-1,e) = h(e - 1); break; case FIXED_2ND_DERIV_BC: C(e) = _BCHighVal; A(e,e) = 1; break; case PARABOLIC_RUNOUT_BC: C(e) = 0; A(e,e) = 1; A(e-1,e) = -1; break; } ublas::matrix AInv(size(), size()); InvertMatrix(A,AInv); _ddy = ublas::prod(C, AInv); _data.resize(size()-1); for (size_t i(0); i < e; ++i) { _data[i].x = x(i); _data[i].a = (_ddy(i+1) - _ddy(i)) / (6 * h(i)); _data[i].b = _ddy(i) / 2; _data[i].c = (y(i+1) - y(i)) / h(i) - _ddy(i+1) * h(i) / 6 - _ddy(i) * h(i) / 3; _data[i].d = y(i); } _valid = true; } }; } } #endif // WITHBOOST #endif // SPLINE_H mldemos-0.4.3/Core/types.h000066400000000000000000000061121172143270300153630ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef __TYPES_H__ #define __TYPES_H__ #include // type definitions, u <- unsigned, s <- signed, f <- floating point, X: number of bits typedef unsigned char u8; typedef unsigned short int u16; typedef unsigned int u32; typedef unsigned long u64; typedef char s8; typedef short int s16; typedef int s32; typedef long s64; typedef float f32; typedef double f64; typedef std::vector dvec; typedef std::vector fvec; typedef std::vector uvec; typedef std::vector ivec; typedef std::vector bvec; typedef std::pair ipair; typedef std::pair fpair; typedef std::pair dpair; #include using std::max; using std::min; //#ifndef max //#define max(a,b) (a > b ? a : b) //#define min(a,b) (a < b ? a : b) //#endif // fancy macros #define FOR(i,length) for(u32 i=0; i<(u32)(length); i++) #define SWAP(x,y) x^=y^=x^=y // fast swap for pointers or integers #define MAX3(a,b,c) max(a,max(b,c)) #define MIN3(a,b,c) min(a,min(b,c)) #define TRIM(a,b,c) min(max(a,b),c) #define Truncate(a,b) a = ( a>=b ? b : a) // delete macros #define DEL(a) if(a){delete a; a=NULL;} // safe delete pointer #define KILL(a) if(a){delete [] a; a=NULL;} // safe delete [] #define IMKILL(a) if(a) {cvReleaseImage(&(a)); (a)=NULL;} // safe delete image // reading pixels from an image #undef RGB #define RGB(image,i) (image->imageData[i]) #define to255(x) ((x<<8)-x) // fast multiply *255 // define an image's region of interest #define ROI(a,b) cvSetImageROI(a,b) #define unROI(a) cvResetImageROI(a) // definitions for the matlab-style tic toc #define TICTOC u64 tic_time = 0; #define tic tic_time = (u64)(cvGetTickCount()/cvGetTickFrequency()) #define toc printf("Elapsed time is %.3f seconds.\n",((u64)(cvGetTickCount()/cvGetTickFrequency()) - tic_time)/1000000.0f) #define etoc ((u64)(cvGetTickCount()/cvGetTickFrequency()) - tic_time) // #include static bool endsWith(const char *a,const char *b) { bool yeah = true; int lena = strlen(a); int lenb = strlen(b); for (int i=0; i #include #include #include #include #include #include #include #include #include #include "widget.h" /* QPixmap QNamedWindow::toPixmap(IplImage *src) { QPixmap pixmap; if(!src) return pixmap; if(src->nChannels == 4) { pixmap = QPixmap::fromImage(QImage((const unsigned char *)src->imageData,src->width, src->height, QImage::Format_RGB32)).copy(); } else { IplImage *image = cvCreateImage(cvGetSize(src),8,4); cvCvtColor(src, image, src->nChannels==1 ? CV_GRAY2BGRA : CV_BGR2BGRA); QImage qimg = QImage((const unsigned char *)image->imageData, image->width, image->height, QImage::Format_RGB32); pixmap = QPixmap::fromImage(qimg).copy(); cvReleaseImage(&image); } return pixmap; } IplImage *QNamedWindow::toImage( QImage image ) { if (image.isNull()) return NULL; const int w = image.width(); const int h = image.height(); IplImage *img = cvCreateImage(cvSize(w, h), 8, 3); uchar *pixels = image.bits(); for(int i=0; iimageData[i*img->widthStep + j*3 + c] = pixels[i*w*3 + j*h*3 + c]; } } return img; } */ QNamedWindow::QNamedWindow(QString name, bool bResizable, QWidget *parent) : QWidget(parent), name(name) { qRegisterMetaType("QImage"); setWindowTitle(name); setMouseTracking(true); setAcceptDrops(true); //setCursor(Qt::CrossCursor); this->bResizable = bResizable; if(!bResizable) setFixedSize(256,256); else if(parent) resize(parent->width(), parent->height()); else resize(256,256); bBorderless = false; bNewImage = true; mouseCallback = NULL; show(); } int counter = 0; bool bRedrawing = false; /* void QNamedWindow::ShowImage(IplImage *image) { if(!image) return; bRedrawing = true; pixmap = toPixmap(image); if(!bResizable) setFixedSize(pixmap.width(), pixmap.height()); else if (bNewImage && !isFullScreen()) resize(pixmap.width(), pixmap.height()); bNewImage = false; bRedrawing = false; repaint(); //update(); } */ void QNamedWindow::ShowImage(QPixmap pixmap) { if(pixmap.isNull()) return; bRedrawing = true; this->pixmap = pixmap; if(!bResizable) setFixedSize(pixmap.width(), pixmap.height()); else if (bNewImage && !isFullScreen()) resize(pixmap.width(), pixmap.height()); if(parent()) resize(((QWidget*)parent())->width(), ((QWidget*)parent())->height()); bNewImage = false; bRedrawing = false; repaint(); //update(); } void QNamedWindow::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Qt::black); if (pixmap.isNull()) { painter.setPen(Qt::white); //painter.drawText(rect(), Qt::AlignCenter, tr("No Image to Display...")); return; } if(parent() && (width() != ((QWidget*)parent())->width() || height() != ((QWidget*)parent())->height())) { resize(((QWidget*)parent())->width(), ((QWidget*)parent())->height()); } painter.fillRect(QRect(0,0,width(),height()), Qt::black); if(!bRedrawing && width() && height() && !pixmap.isNull() && pixmap.width() && pixmap.height()) painter.drawPixmap(QRect(0,0,width(), height()), pixmap); } void QNamedWindow::resizeEvent(QResizeEvent *event) { emit ResizeEvent(event); //if(!bResizable) resize(pixmap.width(), pixmap.height()); } void QNamedWindow::mousePressEvent(QMouseEvent *event) { int x = event->x(), y = event->y(); int flags = 0, events = 0; if(event->buttons() == Qt::LeftButton) flags |= EVENT_FLAG_LBUTTON; if(event->buttons() == Qt::RightButton) flags |= EVENT_FLAG_RBUTTON; if(event->button() == Qt::LeftButton) events = EVENT_LBUTTONDOWN; else if(event->button() == Qt::RightButton) events = EVENT_RBUTTONDOWN; if(mouseCallback) mouseCallback(events, x, y, flags); emit MousePressEvent(event); } void QNamedWindow::mouseReleaseEvent(QMouseEvent *event) { int x = event->x(), y = event->y(); int flags = 0, events = 0; if(event->buttons() == Qt::LeftButton) flags |= EVENT_FLAG_LBUTTON; if(event->buttons() == Qt::RightButton) flags |= EVENT_FLAG_RBUTTON; if(event->button() == Qt::LeftButton) events = EVENT_LBUTTONUP; else if(event->button() == Qt::RightButton) events = EVENT_RBUTTONUP; if(mouseCallback) mouseCallback(events, x, y, flags); emit MouseReleaseEvent(event); } void QNamedWindow::mouseMoveEvent(QMouseEvent *event) { int x = event->x(), y = event->y(); int flags = 0, events = 0; if(event->buttons() == Qt::LeftButton) flags |= EVENT_FLAG_LBUTTON; if(event->buttons() == Qt::RightButton) flags |= EVENT_FLAG_RBUTTON; if(mouseCallback) mouseCallback(events, x, y, flags); emit MouseMoveEvent(event); } void QNamedWindow::dragEnterEvent(QDragEnterEvent *event) { emit DragEnterEvent(event); } void QNamedWindow::dropEvent(QDropEvent *event) { emit DropEvent(event); } void QNamedWindow::SetMouseCallback( void (*callbackFunction)(int,int,int,int) ) { if(callbackFunction) mouseCallback = callbackFunction; } mldemos-0.4.3/Core/widget.h000066400000000000000000000052551172143270300155110ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifndef QNamedWindow_H #define QNamedWindow_H //typedef struct _IplImage IplImage; //#include //#include #include //#include #include enum { EVENT_MOUSEMOVE =0, EVENT_LBUTTONDOWN =1, EVENT_RBUTTONDOWN =2, EVENT_MBUTTONDOWN =3, EVENT_LBUTTONUP =4, EVENT_RBUTTONUP =5, EVENT_MBUTTONUP =6, EVENT_LBUTTONDBLCLK =7, EVENT_RBUTTONDBLCLK =8, EVENT_MBUTTONDBLCLK =9 }; enum { EVENT_FLAG_LBUTTON =1, EVENT_FLAG_RBUTTON =2, EVENT_FLAG_MBUTTON =4, EVENT_FLAG_CTRLKEY =8, EVENT_FLAG_SHIFTKEY =16, EVENT_FLAG_ALTKEY =32 }; class QNamedWindow : public QWidget { Q_OBJECT private: QString name; QTimer *timer; QPixmap pixmap; QImage qimg; QPoint mouse; bool bResizable; bool bBorderless; protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); public: bool bNewImage; QNamedWindow(QString name, bool bResizable = false, QWidget *parent = 0); // void ShowImage(IplImage *image); void ShowImage(QPixmap pixmap); void SetMouseCallback(void (*mouseCallback)(int, int, int, int)); void (*mouseCallback)(int, int, int, int); QPixmap Pixmap() {return pixmap;}; // static QPixmap toPixmap(IplImage *src); // static IplImage *toImage(QImage image); signals: void MouseMoveEvent(QMouseEvent *event); void MousePressEvent(QMouseEvent *event); void MouseReleaseEvent(QMouseEvent *event); void DragEnterEvent(QDragEnterEvent *event); void DropEvent(QDropEvent *event); void ResizeEvent(QResizeEvent *event); }; #endif mldemos-0.4.3/LICENSE.txt000066400000000000000000000033001172143270300147750ustar00rootroot00000000000000MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. A copy of the terms and conditions of the license can be found in License.txt or online at http://www.gnu.org/copyleft/lesser.html To obtain a copy, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Disclaimer ---------- The authors make no representations about the suitability or fitness of this software for any purpose. It is provided "as is" without express or implied warranty. --------------------------------------------------------------------- Authors ------- Basilio Noris Learning Algorithms and Systems Laboratory Ecole Polytechnique Fdrale de Lausanne mldemos@b4silio.com http://mldemos.b4silio.com A number of people have contributed directly or indirectly to this software, which makes use of several 3rd party open-source libraries in the form of dynamically loaded plugins. WARNING: Individual licenses apply for a number of these 3rd party libraries. Please refer to their respective license files for precise details. If one of these licenses conflicts with your use, you might not be allowed to use/modify their corresponding plugins. mldemos-0.4.3/MLDemos/000077500000000000000000000000001172143270300144565ustar00rootroot00000000000000mldemos-0.4.3/MLDemos/MLDemos.cbp000066400000000000000000000115021172143270300164430ustar00rootroot00000000000000 mldemos-0.4.3/MLDemos/MLDemos.pro000066400000000000000000000026521172143270300165050ustar00rootroot00000000000000# ########################## # Configuration # # ########################## TEMPLATE = app QT -= network QT += svg TARGET = mldemos NAME = mldemos MLPATH =.. DESTDIR = $$MLPATH macx:ICON = logo.icns win32:RC_FILE = MachineLearning.rc RESOURCES += mldemos.qrc CONFIG += mainApp include($$MLPATH/MLDemos_variables.pri) #CONFIG += boost #INCLUDEPATH += $$BOOST macx:INCLUDEPATH += uiMac # ########################## # Source Files # # ########################## FORMS += aboutDialog.ui \ algorithmOptions.ui \ optsClassify.ui \ optsCluster.ui \ optsRegress.ui \ optsMaximize.ui \ optsDynamic.ui \ optsProject.ui \ optsCompare.ui \ mldemos.ui \ drawingTools.ui \ drawingToolsContext1.ui \ drawingToolsContext2.ui \ drawingToolsContext3.ui \ drawingToolsContext4.ui \ statisticsDialog.ui \ viewOptions.ui \ compare.ui \ expose.ui \ manualSelection.ui \ inputDimensions.ui HEADERS += basicMath.h \ canvas.h \ datasetManager.h \ optimization_test_functions.h \ gettimeofday.h \ drawUtils.h \ drawSVG.h \ drawTimer.h \ mldemos.h \ mymaths.h \ public.h \ roc.h \ types.h \ widget.h \ interfaces.h \ classifier.h \ obstacles.h \ regressor.h \ maximize.h \ dynamical.h \ clusterer.h \ compare.h \ spline.h SOURCES += \ main.cpp \ mldemos.cpp \ mlprocessing.cpp \ mlstats.cpp \ mlsaving.cpp \ compare.cpp \ mltrain.cpp mldemos-0.4.3/MLDemos/MachineLearning.ico000066400000000000000000012615361172143270300202140ustar00rootroot00000000000000 ( V (~ 00 %(  NN h^( 3HffffH3-ZZ-<uu?0u333HHHffffffffffffHHH333u0'l---ZZZZZZ---l'`000uuuuuu000`o***llllll***oEo$$$cccccc$$$i`TTTTTTBx,,,TTTx0R iPPP6660EH1111$$v&&&```~~~E`&&| 22""p444rrr999`]22%%11%%%>>>lll]T 711++,,VVVTHB**11##s---sssH$>++!!22)))CCC$ 3..++,,``` `1122 i 888`$$$x&&//!!!VVV666$x` 00&&~///{{{***x0--11WWW0{##s00$$x777333{$''""00 YYYT$$x 00##u 999666T --##--&&&mmm !b22hKKK(((!H22**)) ,,,sssH~''11 ggg~ O11!!oJJJ ..(())000RRR-1100'''ttt-?))22c"""YYY?Z..%%y FFFZ`>&&**<<<cl k//(((...lx##u 22!!!www777x((11]___@@@u,,..##uZZZLLLul//**##u NNNUUUl`,,''**GGGIII`W((++AAA@@@WB##u,,BBB444B-f ..:::+++-E--CCC ..>>> --FFF~))++ MMM~H00** UUUH!&&|&&%%y^^^999! O (($$xuuu ..`"""W''11***W2222???333333ssse..VVV??????***x##%%{lllx0----`$$$!!!!!!0$$x11>>>666x$..___!!!!!!x$''%%""r{{{{{{$##s22333666999333c //___000000c--$$""r'''e22JJJ***0))0&&|00:::999K ,,uuuK00..777T 3 //www T..00--"""AAAW 7,,W--llllll11TTT]B{rrrrrr{%%y(((]++!!22qqqH 7,, EEEH11!!''"""0llllll11 yyy022llllll..NNNlll""+++000r$$x33++666x##22{{{BH11 \\\B11++JJJ~~~&&"""888i##s111+++333i&&@@@ GGGi&&| JJJ999i&& LLL MMMi&&| III999i&&>>>!!!111+++ <##s%%(((666333<22**FFFxxx11bbb 722 T..++TTTW..$$,,,44400UUU 00 ?&&| 333---999?r2200TTTrrrr&& ..,,$$$999 00sss 0!!o''(((4440000]1111ggg]]]]11..+++&&++uuu 11CCC##&&|### 7//[[[- i22999----K,,,,\%%%KKKK`11))tttccccu22//OOOuuuu00 11888**22!!!222##11!!!+++00\!!!zzz333333 //bttt??????11b"""ppp11$$$qqq!!!!!!22\zzz11!!!"""sss!!!!!!0000...{{{{{{%%,,222666999llllll..$$xHHH000000{rrrrrr{00f[[[!! 11 ###ggg00---!!##++444llllll..''GGG llllll..eXXX// khhh##3311]iii**11]www0022Y"""vvvu22..]###{{{uuuu`11--!!oxxxccccK,,))!!ldddKKKK- i ))aaa---- 7--PPP22>>> 00###)))&&##%%{~~~11..[[[Z0022<<<]]]]0!!o##""r0000 00[[[ ,,%%%333&& ..uuur22,,!!!<<--0000-->Z i&&|22(( ((22&&|iE##s1111****1111##sEN i**2222--++&&&&++--2222** iN<rr<3]]3-EffffE-??????????????????????(  G j j G I '''<< 2ss_U77+V!!3 ^zxXXX H$$eeY H !((YYL ((WWIkkk F&&]]P F !!qqfwnNNNP Y..% [ YYOl[CCC55*xxxiG++ Gn S n "OOF M((+'''d+<<<t 7PPP \vvq%%%rrreeeLqqm%%%sssHvvpzzzT)iiittbP 'v}}q""11"zzzQQH !!~AA4sss "MM@xxldaaWdddtz[ppiPPPdZwwq<<<M fnng''' "!![[P n""::+ nG%%, G K NNCxxxl##3CCC ZZM Y ? Z==2w z{NNN W½ E22) F ==5kkk !JJA HQQG HOOEXXX CC:66* 1 ''>ooo =i=I]]S"""''' J//&$$$pppJB`  C77,C ! T %x::-mmm%zzmMMAoz CSSI*$$$<||pv??1qqq<Uss_viic5 VH# V)444$Q#mmmQ!!""&!!$$)  "") $ + + (  Hhha !!|@@2   ))-,vvottt V  y;;-000Q7 +Q  `==2rrr  B.ttl""" 7--kkk7 RJJ@  B +ddY<J ##.qqg$$$<F / ##6xxvF 9nH 7{   y? 2 yy 2~ C kk  C~# SMbs~ ~sbM S#DhhD????????????????(0` $HO---KKK___jjjjjj___KKK---O777 . ##ڎ444p """xhhh zucccz 5\\&&&Kq^^^KiiiiNN!!q___9aaa***}--~~~}xhhhmmm )) w {jjj SSSqqC555U˿U!!</// \>>KKKo```s##jjjsZZBBjjjo ,,cc``` \aaKKK<88///UVVUC555qq v {ź___ooojjj SSS {{MMM]]]xhhhiii|]]|9Ͼ*** p___M$$Miic cIqll^^^I4""¶&&&yuTTbbby yii}kkk   / h@Hh!!!IT< [mrrm [<T??( @   OEEI||{٘򥥥|||JJJP ~~~DQ||BBB777F9,,,666zkkk%OO% ;;ZzKKmmmIII;777,,,  SFFggEEE``S]]S[MMM||| ++|||[&&MMMSSRvv(((EEE;WW<<,,, ZzmmmIII $$ zddkkkB9,,,555DP55oIIB777 RZY R ??(  ~E&22{四%%%%ttt::!)55aa)&&^^,,((?? ) )77WW|1%HH &rrrmldemos-0.4.3/MLDemos/MachineLearning.rc000066400000000000000000000000661172143270300200320ustar00rootroot00000000000000IDI_ICON1 ICON DISCARDABLE "MachineLearning.ico" mldemos-0.4.3/MLDemos/_mlstats.cpp000066400000000000000000000202701172143270300170110ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include "basicMath.h" #include "classifier.h" #include "regressor.h" #include "clusterer.h" #include #include #include #include #include #include #include #include using namespace std; void MLDemos::MouseOnRoc(QMouseEvent *event) { int e; switch( event->button()) { case Qt::LeftButton: e = CV_EVENT_LBUTTONUP; break; case Qt::RightButton: e = CV_EVENT_RBUTTONUP; break; } //roc_on_mouse(e, event->x(), event->y(), 0, 0); //rocWidget->ShowImage(GetRocImage()); //statsDialog->repaint(); } void MLDemos::ShowRoc() { if(!classifier) return; SetROCInfo(); actionShowStats->setChecked(true); showStats->tabWidget->setCurrentWidget(showStats->rocTab); ShowStatsDialog(); } void MLDemos::ShowCross() { if(!classifier && !regressor) return; SetCrossValidationInfo(); actionShowStats->setChecked(true); showStats->tabWidget->setCurrentWidget(showStats->crossvalidTab); ShowStatsDialog(); } void MLDemos::StatsChanged() { int tab = showStats->tabWidget->currentIndex(); switch(tab) { case 0: UpdateInfo(); break; case 1: SetROCInfo(); break; case 2: SetCrossValidationInfo(); break; } } void PaintData(std::vector data, QPixmap &pm) { QPainter painter(&pm); painter.fillRect(pm.rect(), Qt::white); int w = pm.width(); int h = pm.height(); int cnt = data.size(); int pad = 10; QPointF oldPoint; double minVal = FLT_MAX; double maxVal = -FLT_MAX; for(int i=0; i< data.size(); i++) { if(minVal > data[i]) minVal = data[i]; if(maxVal < data[i]) maxVal = data[i]; } if (minVal == maxVal) { minVal = 0; } painter.setBrush(Qt::NoBrush); painter.setPen(QPen(QColor(200,200,200), 0.5)); int steps = 10; for(int i=0; i<=steps; i++) { painter.drawLine(QPoint(0, i/(float)steps*(h-2*pad) + pad), QPoint(w, i/(float)steps*(h-2*pad) + pad)); painter.drawLine(QPoint(i/(float)steps*w, 0), QPoint(i/(float)steps*w, h)); } painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(Qt::black, 1.5)); for(int i=0; i< data.size(); i++) { float value = data[i]; if (value != value) continue; float x = i/(float)cnt*w; float y = (1 - (value-minVal)/(maxVal - minVal)) * (float)(h-2*pad) + pad; QPointF point(x, y); if(i) painter.drawLine(oldPoint, point); //painter.drawEllipse(point, 3, 3); oldPoint = point; } painter.setPen(QPen(Qt::black, 0.5)); painter.setBrush(QColor(255,255,255,200)); painter.drawRect(QRect(w - 100 - 15,h - 55,110,45)); painter.setPen(QPen(Qt::black, 1)); painter.drawText(QPointF(w - 107, h-57+20), QString("start: %1").arg(data[0], 3)); painter.drawText(QPointF(w - 107, h-57+40), QString("end: %1").arg(data[data.size()-1], 3)); } void MLDemos::SetROCInfo() { QSize size(showStats->rocWidget->width(),showStats->rocWidget->height()); if(classifier && bIsRocNew) { QPixmap rocImage = RocImage(classifier->rocdata, classifier->roclabels, size); bIsRocNew = false; // rocImage.save("roc.png"); rocWidget->ShowImage(rocImage); } if(maximizer) { vector history = maximizer->HistoryValue(); vector data;data.resize(history.size()); FOR(i, data.size()) data[i] = history[i]; if(!data.size()) return; QPixmap pixmap(size); PaintData(data, pixmap); rocWidget->ShowImage(pixmap); } } void MLDemos::SetCrossValidationInfo() { if(!bIsCrossNew) return; std::vector fmeasures; if(classifier) fmeasures = classifier->crossval; else if(regressor) fmeasures = regressor->crossval; if(!fmeasures.size()) return; char txt[255]; QString text; text += "Cross-Validation\n"; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = classifier ? optionsClassify->traintestRatioCombo->currentIndex() : optionsRegress->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; if(classifier) sprintf(txt, "%d folds\n", optionsClassify->foldCountSpin->value()); else sprintf(txt, "%d folds\n", optionsRegress->foldCountSpin->value()); text += txt; sprintf(txt,"%d train, %d test samples", (int)(canvas->data->GetCount()*trainRatio), canvas->data->GetCount() - (int)(canvas->data->GetCount()*trainRatio)); text += txt + QString("\n\n"); text += classifier ? QString("Classification Performance:\n\n") : QString("Regression Error:\n\n"); FOR(i, fmeasures.size()) { fvec meanStd = MeanStd(fmeasures[i]); fvec quartiles = Quartiles(fmeasures[i]); text += !i ? "Training\n" : "Testing\n"; sprintf(txt,"%.3f %.3f", meanStd[0], meanStd[1]); text += txt + QString(" (meanstd)\n"); sprintf(txt,"%.3f %.3f %.3f %.3f %.3f", quartiles[0], quartiles[1], quartiles[2], quartiles[3], quartiles[4]); text += txt + QString(" (quartiles)\n"); text += "\n\n"; } showStats->crossvalidText->setText(text); QSize boxSize(showStats->crossvalidWidget->width(),showStats->crossvalidWidget->height()); QPixmap boxplot = BoxPlot(fmeasures, boxSize); // boxplot.save("boxplot.png"); bIsCrossNew = false; showStats->crossvalidImage->setPixmap(boxplot); } void MLDemos::UpdateInfo() { // dataset information int count = canvas->data->GetCount(); int pcount = 0, ncount = 0; ivec labels = canvas->data->GetLabels(); int posClass = optionsClassify->positiveSpin->value(); FOR(i, labels.size()) { if(labels[i] == posClass) ++pcount; else ++ncount; } // min/max, mean/variance vector samples = canvas->data->GetSamples(); fvec sMin,sMax,sMean,sSigma; sMin.resize(2,FLT_MAX); sMax.resize(2,-FLT_MAX); sMean.resize(2,0); sSigma.resize(4,0); if(samples.size()) { FOR(i,samples.size()) { sMin[0] = min(sMin[0],samples[i][0]); sMin[1] = min(sMin[1],samples[i][1]); sMax[0] = max(sMax[0],samples[i][0]); sMax[1] = max(sMax[1],samples[i][1]); sMean += samples[i]; } sMean /= samples.size(); FOR(i, samples.size()) { sSigma[0] += (samples[i][0]-sMean[0])*(samples[i][0]-sMean[0]); sSigma[1] += (samples[i][0]-sMean[0])*(samples[i][1]-sMean[1]); sSigma[3] += (samples[i][1]-sMean[1])*(samples[i][1]-sMean[1]); } sSigma[0] = sqrtf(sSigma[0]/samples.size()); sSigma[1] = sqrtf(sSigma[1]/samples.size()); if(sSigma[1] != sSigma[1]) sSigma[1] = 0; sSigma[2] = sSigma[1]; sSigma[3] = sqrtf(sSigma[3]/samples.size()); } else { sMin.clear();sMax.clear(); sMin.resize(2,0); sMax.resize(2,0); } QString information; information += "Current Dataset:\n"; char string[255]; sprintf(string, " %d Samples\n %d Positives\n %d Negatives\n\n", count, pcount, ncount); information += QString(string); information += " Min - Max Mean , Var\n"; sprintf(string, " %.3f %.3f %.3f , %.3f %.3f\n", sMin[0], sMax[0], sMean[0], sSigma[0], sSigma[1]); sprintf(string, "%s %.3f %.3f %.3f , %.3f %.3f\n", string, sMin[1], sMax[1], sMean[1], sSigma[2], sSigma[3]); information += string; if(classifier) information += "\nClassifier: " + QString(classifier->GetInfoString()); if(regressor) information += "\nRegressor: " + QString(regressor->GetInfoString()); if(clusterer) information += "\nClusterer: " + QString(clusterer->GetInfoString()); if(dynamical) information += "\nDynamical: " + QString(dynamical->GetInfoString()); if(maximizer) information += "\nMaximizer: " + QString(maximizer->GetInfoString()); showStats->infoText->setText(information); } mldemos-0.4.3/MLDemos/aboutDialog.ui000066400000000000000000000165161172143270300172600ustar00rootroot00000000000000 aboutDialog true 0 0 403 337 0 0 About MLDemos true false true true background-color: rgb(255, 255, 255); QFrame::Box QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; font-weight:600;">Machine Learning Demos</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; font-style:italic;">by Basilio Noris</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:11pt; font-style:italic; text-decoration: underline;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt;">Learning Algorithms and Systems Laboratory</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt;">Ecole Polytechnique Fédérale de Lausanne</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt;"> </span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="mailto://mldemos@b4silio.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; text-decoration: underline; color:#0000ff;">mldemos@b4silio.com</span></a></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://lasa.epfl.ch"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; text-decoration: underline; color:#0000ff;">http://lasa.epfl.ch</span></a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:11pt;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; font-weight:600;">Acknowledgements</span></p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:11pt; font-weight:600;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt; font-style:italic;">Many thanks to the following researchers and coders for developing and providing different algorithms used in this software.</span></p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:11pt; font-style:italic;"></p> <p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:11pt;">Florent D'Halluin (Linux ports, GMM + GMR), Dan Grollman (SOGP), Mohammad Khansari (SEDS), Christophe Paccolat (Linux ports), Stephane Magnenat (ESMLR + RRMLR), Chih-Chung Chang and Chih-Jen Lin (libSVM), Yummigum (icons), David Mount and Sunil Arya (Approximate Nearest Neighbors), Davis E. King (DLIB), Stefan Klanke and Sethu Vijayakumar (LWPR), Robert Davies (Newmat), JF Cardoso (ICA), Antonio Gulli (KPCA), the Eigen, OpenCV and Qt development teams.</span></p></body></html> Close okButton clicked() aboutDialog accept() 351 38 233 29 mldemos-0.4.3/MLDemos/algorithmOptions.ui000066400000000000000000000100121172143270300203510ustar00rootroot00000000000000 algorithmOptions 0 0 636 220 0 0 636 220 636 220 Algorithm Options false 0 0 QTabWidget::North QTabWidget::Rounded 0 Qt::ElideRight false false false false Classification 0 0 Clustering 0 0 Regression 0 0 Projections 0 0 Dynamical 0 0 Optimization 0 0 mldemos-0.4.3/MLDemos/compare.cpp000066400000000000000000000075111172143270300166140ustar00rootroot00000000000000#include "compare.h" #include using namespace std; CompareAlgorithms::CompareAlgorithms(QWidget *parent) : display(0) { compareDisplay = new Ui::CompareDisplay(); compareDisplay->setupUi(compareWidget = new QWidget(parent)); if(!parent) compareWidget->setWindowTitle("Comparison Results"); else { parent->layout()->setContentsMargins(12,0,0,0); parent->layout()->setSpacing(0); parent->layout()->addWidget(compareWidget); compareWidget->layout()->setContentsMargins(0,0,0,0); } display = compareDisplay->display; connect(compareDisplay->resultCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(Update())); connect(compareDisplay->displayTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(Update())); } CompareAlgorithms::~CompareAlgorithms() { DEL(compareDisplay); } void CompareAlgorithms::Clear() { results.clear(); algorithms.clear(); compareDisplay->resultCombo->clear(); } void CompareAlgorithms::SetActiveResult(int index) { if(index >= compareDisplay->resultCombo->count()) return; compareDisplay->resultCombo->setCurrentIndex(index); } void CompareAlgorithms::AddResults(fvec result, QString name, QString algorithm) { if(!result.size()) return; results[name].push_back(result); algorithms[name].push_back(algorithm); bool exists = false; FOR(i, compareDisplay->resultCombo->count()) { if(name == compareDisplay->resultCombo->itemText(i)) { exists = true; break; } } if(!exists) compareDisplay->resultCombo->addItem(name); } void CompareAlgorithms::Update() { int displayType = compareDisplay->displayTypeCombo->currentIndex(); QString name = compareDisplay->resultCombo->currentText(); vector result = results[name]; QStringList names = algorithms[name]; if(!names.size() || !results.size()) return; int rW = 150; int hPad = 20; QSize boxSize(rW*names.size(),200); pixmap = QPixmap(boxSize.width(),boxSize.height()+2*hPad); QBitmap bitmap; bitmap.clear(); pixmap.setMask(bitmap); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); //painter.setFont(QFont("Lucida Grande", 12)); painter.setPen(QPen(Qt::black, 0.5)); painter.setBrush(Qt::NoBrush); FOR(i, result.size()) { QRect rect(boxSize.width() * i/ result.size(), 0, rW, hPad); painter.drawText(rect, Qt::AlignHCenter | Qt::AlignTop, names[i]); } switch(displayType) { case 0: { QPixmap box = BoxPlot(result, boxSize); painter.drawPixmap(0,2*hPad,box.width(), box.height(), box); } break; case 1: { QPixmap box = Histogram(result, boxSize); painter.drawPixmap(0,2*hPad,box.width(), box.height(), box); } break; case 2: QPixmap box = RawData(result, boxSize); painter.drawPixmap(0,2*hPad,box.width(), box.height(), box); break; } display->setPixmap(pixmap); } QString CompareAlgorithms::ToString() { QString text; FOR(x, compareDisplay->resultCombo->count()) { QString name = compareDisplay->resultCombo->itemText(x); vector result = results[name]; QStringList names = algorithms[name]; if(!names.size() || !results.size()) return text; text += name + "\n"; FOR(n, names.size()) { fvec& data = result[n]; int nanCount = 0; FOR(i, data.size()) if(data[i] != data[i]) nanCount++; float mean = 0; float sigma = 0; FOR(i, data.size()) if(data[i]==data[i]) mean += data[i] / (data.size()-nanCount); FOR(i, data.size()) if(data[i]==data[i]) sigma += powf(data[i]-mean,2); sigma = sqrtf(sigma/(data.size()-nanCount)); text += names[n] + "\t"; text += QString("%1\t%2").arg(mean, 0, 'f', 4).arg(sigma, 0, 'f', 4); text += "\n"; } text += "\n"; } return text; } void CompareAlgorithms::Show() { Update(); compareWidget->show(); } mldemos-0.4.3/MLDemos/compare.h000066400000000000000000000013161172143270300162560ustar00rootroot00000000000000#ifndef _COMPARE_H_ #define _COMPARE_H_ #include #include #include #include #include "ui_compare.h" class CompareAlgorithms : public QObject { Q_OBJECT std::map< QString, std::vector< fvec > > results; std::map< QString, QStringList > algorithms; Ui::CompareDisplay *compareDisplay; QWidget *compareWidget; QLabel *display; QPixmap pixmap; public: CompareAlgorithms(QWidget *parent=0); ~CompareAlgorithms(); void AddResults(fvec results, QString name, QString algorithm); void Show(); void Clear(); void SetActiveResult(int index); QPixmap &Display(){return pixmap;} QString ToString(); public slots: void Update(); }; #endif // _COMPARE_H_ mldemos-0.4.3/MLDemos/compare.ui000066400000000000000000000057771172143270300164630ustar00rootroot00000000000000 CompareDisplay 0 0 421 374 0 0 Compare Algorithms 1.000000000000000 false 0 0 0 0 12 Qt::Horizontal 40 20 Box Plots Histograms Raw Data true 0 0 395 314 0 0 mldemos-0.4.3/MLDemos/drawingTools.ui000066400000000000000000000273711172143270300175030ustar00rootroot00000000000000 DrawingToolbar 0 0 32 300 0 0 Drawing Toolbar false 0 32 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Airbrush</p></body></html> ooo true true false 0 0 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Brush</p></body></html> o true false false false false 0 160 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Eraser</p></body></html> X true false false 0 277 32 20 9 1 255 1 0 96 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Line</p></body></html> | true false false false false 0 128 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ellipse</p></body></html> 0 true false false false false 0 64 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Trajectories</p></body></html> o--> true false false false false 0 257 32 20 9 Class Qt::AlignCenter 0 192 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Obstacles</p></body></html> Obs true false false 0 224 32 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paint Reward</p></body></html> +/- true false false mldemos-0.4.3/MLDemos/drawingToolsContext1.ui000066400000000000000000000064011172143270300211200ustar00rootroot00000000000000 DrawingToolbarContext1 0 0 196 48 Drawing Toolbar 10 20 70 22 9 1 Uniform Normal 90 0 31 20 9 Count 90 20 41 22 9 false 1 999 10 10 0 61 20 9 Distribution 140 20 50 22 9 3 0.001000000000000 1.000000000000000 0.005000000000000 0.025000000000000 150 0 41 20 9 Size mldemos-0.4.3/MLDemos/drawingToolsContext2.ui000066400000000000000000000065761172143270300211360ustar00rootroot00000000000000 DrawingToolbarContext2 0 0 195 48 Drawing Toolbar 130 20 60 22 9 3 0.001000000000000 2.000000000000000 0.005000000000000 0.025000000000000 20 0 30 16 9 Angle 80 0 41 16 9 Width 140 0 41 16 9 Height 70 20 51 22 9 3 0.001000000000000 2.000000000000000 0.005000000000000 0.025000000000000 10 20 51 22 9 1 -180.000000000000000 180.000000000000000 mldemos-0.4.3/MLDemos/drawingToolsContext3.ui000066400000000000000000000150771172143270300211330ustar00rootroot00000000000000 DrawingToolbarContext3 0 0 350 48 Drawing Toolbar 130 20 50 22 9 3 0.001000000000000 0.500000000000000 0.010000000000000 0.025000000000000 10 0 50 16 9 Angle Qt::AlignCenter 70 0 50 16 9 Width Qt::AlignCenter 130 0 50 16 9 Height Qt::AlignCenter 70 20 51 22 9 3 0.001000000000000 0.500000000000000 0.010000000000000 0.025000000000000 10 20 51 22 9 1 -180.000000000000000 180.000000000000000 190 0 60 16 9 Power Qt::AlignCenter 260 20 40 22 9 1 1.000000000000000 99.000000000000000 0.100000000000000 1.000000000000000 260 0 80 16 9 Repulsion Qt::AlignCenter 190 20 30 22 9 1 220 20 30 22 9 1 300 20 40 22 9 1 1.000000000000000 99.000000000000000 0.100000000000000 1.000000000000000 mldemos-0.4.3/MLDemos/drawingToolsContext4.ui000066400000000000000000000046451172143270300211330ustar00rootroot00000000000000 DrawingToolbarContext4 0 0 127 48 Drawing Toolbar 80 0 41 20 9 Alpha 70 20 51 22 9 2 0.010000000000000 1.000000000000000 0.050000000000000 0.300000000000000 20 0 41 20 9 Radius 10 20 51 22 9 1 1.000000000000000 10000.000000000000000 100.000000000000000 mldemos-0.4.3/MLDemos/icons/000077500000000000000000000000001172143270300155715ustar00rootroot00000000000000mldemos-0.4.3/MLDemos/icons/_obstacle.png000066400000000000000000000060321172143270300202330ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FEIDATxQ =e](DYtzXQy<hrVHIDp$֞-[kퟭP,9Y*W>=y+ Ag5E9*HQ:m9L-JQԄlĸ8ҢE[ 7t4? oZ␃GgDo nj@Q(Б@}2^6S]e m ف8Fi:f'1:Xm@eBs*ڵZ1^t?KROsȻuN\wEz{|<#p ]h;IENDB`mldemos-0.4.3/MLDemos/icons/_trajectory.png000066400000000000000000000062031172143270300206250ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATx?kAϚlAJ%@@w`TiS 1RiFP,DARZr1ies'[dvg;ga& 3`̀l|E1?P,ZxcH)[) )Jw"os lXF[U_xanckxׄ5ڣ:EnG,5 ^#f !͸VԷpI{(:)?{g<:i(F`kxZh H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPIDATxMA 5W DtJx\v0GْR&̄pvl1w$ckpr3J<(3p0y4p2Zz(95湩ҫ.ё$1jMRU-4h eUi91#]A{Xc=vMs^\MzհskQnvQ(jh/Xmc#-e58".@ - }t/& ì.9w-X{IKe#2m&sVpIENDB`mldemos-0.4.3/MLDemos/icons/algorithms.png000066400000000000000000005004061172143270300204550ustar00rootroot00000000000000PNG  IHDRx pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_Fv1IDATxwdY}ߍ97TNttLeВI(!ǒ-Ɩz,=6-KXHlaN*W{OqnU 35lwuw{7D)`0  ``0 0 ``0 0 ``0 0 ``0 0 ``0 0 ``0 0 ``0 0 ``0 0 ``0`0 8`0`0 8`0`0 8`0`0 8`0`0 8`0`0 8`0`0 8`0g?-BTPPT (`()%,@ R)B`[ QR*8)%8Q (@ B۲)DzT R8@cf p!`3P"`|( Pp!z>l,(_)$,5p>F\!(#X-uXCZE b1KC2C6(y E'B-X5Jâ D RRJX+V JTR%ZbZ3)PBs׶V`Y ~NQy& /:68`jsCE9p0FApؖJïۅB¶!|~!`1 X8焄6 RAH (l }HtO(RDR) 0 U2@mۺ=8`0jRڌhĽ h,ѱ7K9D`0PJF";2k&hyk7)Q2 +E#T"l2V<1O &.aBL"`0 WIbX\;m1M$H_gmk!9\`0: D-Ʈ鸡%k'Q2՚{r9\`0:Rnmo}D:oNHJ)z:m{]۾N1`0 +.DKqo޴}1BO@(%Hc>67?F`Cg0 ÕR9yݶd< B R z__W;ْNA>`0L:& `0 ҉nHE#.Pv LR voٚMt l0 F)Bޚk\Ju/8ΓuCX4r`0\9HH<mt5c- jؠSsbsok6zs8 `2b;ڲmhf/ȳT5#=::x- pyCIٖuU\G\ۘXe#={~V`0.o8;z:nٔq,, ` MR 6uw[G'Ӊ낀wCk0 ekSk w;2C)]@ۅTBRA PJvH)]s `RP>֩VUBHK5*p!p9rl߼B.7`0 il պ g$8}R2l@kR-\ paGznrsR )*UKk%f59ޒycSF`0 Wpo5sΉMT+2J:T ƏTRRXY+\ Ɔn8!Qs `xű[GoׅZ=j2BBJ (p.k[*lL v)g`0 `[GQ75B F8 } }\(KEu[ƇFk Jy#:ܲy.Q <4Ͳ=Da@ ptRp̖H)w(s `.vn{@: myXRBA7K9hA2 Bhmt2C}mw{~j΁`0 ?]՚kx:Z :{0@S Q! K 3r̓ }P߭xf. S U[6:7^|*5==?_;_JRlH)PX+ՐN&{rn˲X`0 /?J)@; #J5*U}@4RzJ)c@&8T 5=عehu@`0^vRH'oxpo'*5bEp F (b=ፄR0BA)P) Ĺvf`Ž-C7ڜ`0^߶==-wIP0,ޓ((`6{w(,!$g =?R==92w!MC`0 /X;=GOCjiåRXTnlT:L(#` vJJSyAW9E`0c`dvq rT 0`(b$87 .QJa[L;a%B@ȗjF"5120#~tm1P+BO\ X+V`Y6vMl,`0 /sљM&޸gjd0SsjkRJ[6kmYm0Hs\1.O>!E)l+a!n :ض[Sm 0 y"r鑁׌nK,`[ hbJ L aP(,ؖ6eQ] plNn d)ec a`(kahGw;,FGX`0 <7ݓ0Ģ.V eec6X! RRn; Šmy,FJt:!4fBU!JCmCm!$ʕ:b-Dm`06 Td@\CͫC*T h˦P(WQ:ݔhwl ?''`1 !bQ-,+) %ihmj!::Vךj0 åm6ݓX\-,D.C[.%l!qF =|_2E6R 2`aa\&JmDkpxfvD]B6sj `(Ե;o3k=DFmljC24bQWζ |߇X p1!"4PXb 4tTPJ[*`lSotͯBQJ@`0.Fz޲mlXXö,p! D&k;"N!s:6׵ 9< .m\FN:,//-H'^BTJ q%B{{; po$?wjt,F( F Zh$b8hA,⢫׿xꩧÆH)QTp݃zL*1Pl@;jBB (=vcdv!9`0ݖrǶ׎nK-,p!$@o-W8t|QxiU$P D\L{)2R KKxpQAĵ p0\7RrpPah|=P`0 …Hwܞɱ1b|3(J♙%;=L" J |ΑELF1;s淰x|gjl=\kؖje:Z2C+"k?z[`0T  &c+!FKL) GXO Ro@AJ-' JQ J߫cS\K+~ ޥNF:@v~y,U@RŬ+Od޲hj fV޸ (@!, ;XY+#:6R\upq|xk_'Nяb|lEtZR %zP DHpJ:Nά`zx0c[sߣ߰mWI Pn6e;ӞJv'b3|`0o,!۱=cejˍ+tR]TjWO3sO$Uu?DP,B{ ǂk[R`"uP)brr wyWz\;ӃG>_@PUXl Gm0h. VKubG L-vL1>|woGxV*e& Yr["}@{mȶҮcYΕ&fľL2'gPj^]k3 H)@)k[h&q!T*U\{`ZgY/W* Etwb߾?3t;@k.5 H @ln .+0bqvk[֊/WKPVB  QD6"#uO8ZۊʷH$ R))մE5uC}zZl{əyU7ѡԓG L²lj(|+i%Zr#@ $b6uu :ј{GNȖko}0 a\-ݚ}`rs{g;ɦXɗ .";l۲ !ne:υ!OԾR 0t?Y@&2z,9fBKKزe ?ǎ+x{FC %@ȥjusEtopl-h_p5K(k,=9z}]Gܷ9k`熔*p15z@w-S#S۷ wwu GC+(VRJ!{5:o/R +@KAlXΎ\w܁-TRꍦ(ꞇ'O"Hcr _@~m mY  k$K R),0\ĞQ:ݞL:Ρõ#X-TV t#u{vM%zRˁ`RBD<꾡-s]#Ɔ=m--A`%%WV ҞMCZKk6#yu]K4Zwowy'.P,ȋj>#**N>\.Cu)(,JADzYebkwNNţ9+A*̹@yS\Zj5;'G>~@OǻR[)e˃`xBRRձ]k \{`ۖ\a5_FTAE]IPJ;5N:1.*j\&tE:JCXEOW+N8W‡>!jS0`$DX&''q<r8j5 6@ a3-9D#"v(Ypoj[y_S _-AAuT#uƣF'"sKٵbs0cFn;0>лiP%"V@ P?}c=;=\W0^Ǧnk8rrX$|izܶ(|---? XZ^'r^ЊZX;wġCpϏ~׽ TX^-B)q$4ԙFV8mbˑ32@ޘA SDR(xI!uMkb'Ʊ쉳 |պfR`0jHBQJʥSwo2:I%\V,Re $-]Ǿ{":C*UZ- >L"%%,ہL3gN`ffo|hiiZAyzJO^GPDgg'&&&}KĖ >l *TDB=-35{*o|7\ODTD:A.ƤcQ:ǶZP '_n +TRjOql~g`xSwW(UjZR {+ B~`5\-\P[[\[ f9\[&&PVy|>r/rz?cy!q7 {Y ulPBÆ@K72B$tCX^-Tx-J+NΙjfkn( eT>RF {{{GK):`0\B4tヽoعex˶ѡ֜ J@s ?:J@Hs\cХJG\R z,lIc8l)|@)O}(Jjm #BMrGO#=[_p6[ = BB jM7.@sΩvOvdS{(̨`R`B|kĵn˽m|[6oMZ#_R9#bmBO\/ڱk7KRzǡ[#_#!uJ0ۊ'8}?bjj wZ9 .4 ;ԃ1PVq)7_2l&I'@íF,tp/jJ !Oczd(}|^\?T<ܠ@px`e )t ȗ*[* _%mf [Gޝ 8 p5 VQrҽDgZsoڼN8 K+(5. 4\@+%ʤqցJǩ%H)uyȦ# Dav(/_,1.?)}/\APRyGŬ&d]f] (K~W_װ1t \\`[^("`a(PR pZomj+](h=gJ:(E JfJ$,E( $DO  /p8lM7D"v33W*C2>`RZqcQζ#zL2?z TzZ)s1 ~f;r9q{;[P,QxȦc|"&G2W0f_T*ťepA/ްwJ)Rmn,յ58k#R\5¶_RӕΓ(˂mP P@( @Rb~旀"H\ uHu܎Nu-,})R (vc;(fzwMtَͰVFR B*H@)H) ?@Œen뾟ңBOI>Ƕ:6 eD,2) p`a~nysဖs:lYMo8`]0AD޵_q'119jՇJ18@RpJ V etfpcg~ya0ҕ(P±t@H(@ֳB(H@TS:cpr6dR1lFu2і KYYs1 m 8m7 mOvRS3kB!":NPl#}yf>$w^}⎺mtưZӿ#M@:ei@xpmb֭(+B@MzWLcSDBk, jAOO>'Ɔږ^q -# B"8|ytS ~@)KtX,%2sAX5J5Tjz:U&R7v/F~K"c0^!bKy{K:S7ݵؖ][FZ2ɔsf~gA@ђI!qQ{=R@( WR J.o=XȦOl+5pB#:4/8Th$<jߏZj )[G fɆ2mP<8`T$B/ck`[x1ס1tc`@)sFrOcXnPu튱 K, mñ-8Tozj4C6[I8y.`.>SL=~{Hh0~)~wؖ澎֟tѱEm,D{kY(0JTj*4ZVXb,lnJaYnڻm,0{媇J̓TшJ(Q"2ԍӧN_"'҂Z#su/\p<|'R rJe] X}gffى~8s,?~1%ҏaD+BKF 5uK.|?xeV9--k' t_?H;R!k =u/j";&ܲmmEQ2 z;7с='F:P5 $\EXJZ @ZG\R4Fز((ۨn"\عe]c}8rjccqBZ=8EuFN?](w'p7Vb7R)y;;HT+ W#?1j5@)uI'1JNc˖-|I<Ȥ" 4OXsYh?.E\ئ~gjxCcWJbYѱ0mV8-@ B; E,PT=upNڂ'm_$obf RJ;:2tnֱ{&F=bibI-Z,Z2 D]j5/@.k~}t¥rgr3<ږM >1Ppԛ2=8G2)P?G&|͍Z!%\yA_J哧W־Mhkk"!hii 3OBP(0?;v஻C=ɭ&cZWp,%#ip J)pmGOϼOJۗWad)EX6Q,EA6"N%X~ ;:o~F)ju)K'Ҋt"?QS>,B*D2dOދvmYs 'Eؔ"!Vn \XXD"?Ap :P OI>O b6g6u~r~}\X ((H'"kCGkkMױ6N PhͯdxLZ GsxAPZ$35}ݮwlp:|e>0 JͅhԮL*ηlڷmt3T{( YfTu U/0GP86C"c[PPMTbp,ǁeYn\jBH;ƽۦW5r<(c(kh%s Nͭ@pm[1ç>idYLOO^?vƴB"G*/j3 X.,?_98CrQ'};~}}}=?~ђ!O6|(e4Rn޷˲}9xHAaPJ`Y?=?VWіaSO;r$l2ÑAjpy D oN x>GRZRX'G\cCDŅVm.oQ?SJuE\\&#}]o8m˞mCT<.$X"e0 $}%JR-lV e*#dJ`Y\džp];#}c?tbzulHl(ÿ'w(ːR>/sD"ID m ٣G/7'p[ZT@A$]ϜJކ?F,TkP uF&GGKtJrH- ld)nڿm۲9/p|X~Qy`"uQ|D]$oob֭X^YYF\کT T'/$o㙇Bo?mayY;zbBQױ}N|K3:׵A) ErѣT7r! (N,#bGص;&98{tuގlKK˸p!# qp @F)4 H)|+e8v{&5-}ђNM)ɘ = 1ą%[6ӣF2̲avq xTR媇rCZC pٔBBD"f1KUԼT, ۲PL ]hͦAT=jKX<՚vNE9|QgJ9]a#MmxG{n\uU(Kj)#@\ Ttǽ/#O?o_߀gCXD&:ٍ{~>ɟ`|<.a, !(R^(f hZC)SN#o~m89#o1:u:cс_] #,Z7aϞ=(򗾌7ۨTx[ j%yc5ȦӈD"cBd < /niCZE"n "G(>+ƛޒwۂ!HE$,EZ‰˸?3J,\ᒆ~C߄6Olc=SN6 nG:pHXͮXk&A%T7@)(e)90Jζ4356D6uO.e^Td.ë0E,놶\֭# eڳY+>.`T!uzZsVQTju05g^K𭡅؈".gpXY]E$bbrR)8n9Jù:9d8(TJ~B<"[?0;3?---Rꢽr8QT*x"~^6`@@w O\6ƌ^hgNbhhV7~ʵ:WJlJA p ld&6(@!/Dxn.8i.ë+{c o::i|/(ef\DaYQ3RLv|1ׁMuXzORC"D*% E9|?N>h4;v`mhmkc=3g6Wz-L2\,@]RQ7 :x+ sxشi9GюS tRwێ󒿮H.=P+?#GG:$LF}^*JJ* E۷vٻ?zx˲`K !d!/X\)㦽=|0)qY>ʥM DmmDQ<#=`em7pКcfj@OLغCPn@4 h `A76 Yo@2ߙIؗ*lm ~  x8b,J:h%3+XZ+C"k11)a[dtd {9 ;GR[ni$IzMnPD)6v>1 QƢuc8y|!|@P@]&PJQ{(Ţf2_w/X ~f>7jm_b Ǐb׽ gT*caa~}?c$ZI̯a " B(qSG?t̻"sYBBc! "j:R$Zr9l۶ ]]]ýރ/}˸q-7c=n8XY+Z!Ҟw8S( %R (꾏g,!_+kLţCm'gVpe2n[l_,rӎ-#;7vSHWG"C6!bcRO)I s0Fg0J/0! N!âΞ>Ǐcfv2LLLbzz=`a-_P\(#w޸gۻ(Wk5BJXfWE^v,-\RQT x%I2yP@<ích<ٳt6:sFM!|;v_bJ]\1]R`6CTb7/{>l#מV{Jƛn$}Q<7\wȵvBlIlW %Bv(J3ytg152Go࡞cgg{D&pY*CpYl޼o}/ 7| z8-p $ET XYc&lGOkN |>zx,|~Ag PJ!le_0$sͨ:EE88} :;`Y6>~W R 'ga[75zx b n~NM)G# Bp@$A_o/cxSOaeu_FGǐKucvTj>(#pPdȩ'J+ R]B: *bba|,zZq@&Ͻn;5-JrL`lRؚI'~fm#Cz;u_#3[#!J\c%_B:B)xJhCLIԶ@,X wPC}\t>fϜ?'x|صk7&(W(RJXVh.)n:D:?apsXid33gO|h3<@<C&B$F%G:Xoz&]/I%cs=Z@&EZm}](Ujf?.ː~>Yc]A);ݶ;s7]5=<ԗKZJJ b<dʼn+PRd"L2Gl-+ шt $N:H$o _7 8ZdCr[FVԶqei<< ę1֫ XžmqϏ~o~>5`.|o\K2 ҩOzɦ.{ xAflcau BL҆1cN`}_{? d )-p.zl/~;~ /ïPyD.(պZERnߎ-[SO?xAEpMh B R\X}lRR:(RȗR3^bkROi}cZ ed7N\{aQ *lp ώ^?PzkD=#t뛡$%M2yA$op;y+V~b/Iν߆4y3).:t1Tw>t/L\?,Q@ĵGHHn==Ry,PԔD5χmljAGKDOp8j1~QX @ZHcH%pW1?cG.% =~@g1f@fw>o~}T*AJ\L.xdlFY_k>X2ss%Ģ ^.cT8u :>} g9][w}R 85r %>8N]UG~Gl^yi[B@p7 . 7R*T*bL&;wb``> :1 5EK5-Ar!F('P7/B;JI`IAu_Zul$xCgܶlydْMR)C\uʦ"K)0*4:j]Rxpeм9c54^F@l4?/Յr nf&E6(46Y|Et_JȆg=?@18Ռk%E{Y89Y4sL&" ǶHcK'pfaJpc.kzd-í]--Z V/V ~q! HYCOg{;8JN-u,8nnP mdD 5Ϟѣ1;3q15= r-XY] Uو/R,^ګv<իNpA]c%{{K W}oyqwbeuAvpΒt:\6Dңyf.v]8zyuibٹڵ ;5==4lF =pS-R_yeRGJA(^9_oy^>}@ R cӧquJǩPJ.S}=&Da1"WGO-Xc?=9L羃;O.}]*+!8vxaC5!'$$0 h8k B(^(zܲ^T)4 B6"sD(B_A6|g9 %պs\P4t3&44m @hÉ0v@7D荋;i6stB~B驔pEiyp$,ָVP(Q !$oe~ `Y\aCe 8_ E#}@Q]!!Z^7PkU<ٖ8g6~C كk[Kz 9o!%PQ)PgDJT=8V%tgqz~~ $%յTN[p LɘKK8z:|NLNNbddd fw^2к>7vϣa[nBOKѰ)[YcQ#iߏRR|h>Ax<\.n{2d.,d@^}=\IݺECJ² 7bSOm1^wHum /bC[[KXQ,G|?KjR VRs=tKiO8eW9y`h%Tʺ&E$²ɋ:3 >Z[qua|?w|?n-=*| @S P !Ak`HJzaW ;9WcOK8zO/}PJWn0:B׆?t17)u`C@AAllpT3lMs6dt4? KN6dw66Fl()I @ @X 63hM!@Hx̆mِ2|+lj!J^[^}-,XԂU7R77N[SR2r5D C2ܕIZaaj̓ O5?l^]((2lf!#_&[2eq!Oaeq]m8\CH g\{>砌`aܰ{WxW& t`1L*l: y>#DcQs#pdb j t xӛބow'~] K+%EYB\t+!jR}]i7>K'~ǏY\; Z_\+mtØ7 :#r!`c4~@3f.s ls~uT~wbYF#B6KGt$Ꮥv }j=@TrC#WaCj8JG8K Pp\ (UBmP/24>\DžT .2f1wOHږӳ[^C2LƵ=qlDc#p hk2lن p~O<j:p^ ?=܋}sj1T*hm"N"ux!e)QY[~١a ܻ1ITe$<ƛSw? > O7܀1t%-A l!udM ,86fP1;e$_J4C@ pXn)5a&_nHKupN:%h}=n-QxfwpN@QӤxNdsIAף;(Y?Zn p=mOկͨ~5^(@Kc ,!{Q@r}[V^l0ׅ E/Q(1$PqP(B$h^CR$T,vvOnꌯxi IH_>RXqRqc@zO&D:B"q =rKK hokǶ1==h4zZ>i C3 B@)e D fob PĤt1]w]-x{~ԧсS\AjJt:\. "t.u =>@]oѣƲ;ߍtgށ|/wa%_ZۢBVȉEvծ_?R?}OF@dA AZC\F\Au sH O^!NcddB |g>ܹr FђM,!n$˚.Tx5,Kk*58lO"w9ɹRXi tР6žctEXuc,09Elې@ izFFisijoC?9?C76|sN iztmg:3 HSrCrCkK )H.`NjKꔩXUe*0߆gV!EX6'2p7:r)*x," HBp~Ysj1zuoGNl?=2q"x fӜBR H) $:gH%utm2fJtRĦPX]ĉq1=C޺=\b~aq'MKYhԽ \uA1@JK U,2ir)U$kwM|.p)1 ˢp m!+O~ccc8;3'.uZ xmm9De{Q=/ `<G  yuZַލבd0Z<1@)L,@3ގ95p7 B2Rh4h4R4Rr jB ۶gML\& ҂_~?=qÍ7ma5_B5\[R ժzӛT ף*U[с[ENƣ8RԿ5r(!mֿuQ@7_P68 ſ @soYoCA=87F |aGLS n+g%2ͯ^#JҮ '}H`O( ; " W\adXpj63;eiՆBRu+NFJETx=m;v_}Cg/٫tT# %L1¦M-. G!B,bCx5:} Oj]mX^+ P2͵sH{G{I whFR)qAlJaYlG%Q*@@՞C: s#DZg \fc\8.DeB)p82JO> |̀RJڲE(! ҊR{bmq7~7zݻ"4+u'@H'~b)PzqB}@6=?sFCb߾}jxcw?zN  B X1P@PG:ۮ_gw;xe?:Z`HRFE#J%+exRXTO ض̞I =]yb``~?xp`o*-cXP0EyȔb N8= /m-#D?~pV,Wrf΢ au2QR96Y!SP8HɆP sF1čyXWޣF?P2Ͽ.Q -;wn n $v`Ô =~#!p"&Gzp"pRTHQ.Aĥza |tfr8G X63.2ȤmRZwMnz\<'fWqzv Z4֍~4 6Ӓ4|0JL݆T<"|q<޼\ׅp,--V{owSg88e딂-9jlCaq=*qXtplݷ±,~CP.W~[0669!aY>X}udid)Ž^zU;84v,],"zQg9W]}sػ:wONZz,0*<cǎڝ[=yoս.A֕ AR8xS0:ЏG-؁Bj'p+}| {Y!B@- Qq]D 2 =ш" *  <BhE@0\KvepPĵ?BAO/7AD)F)"7x~IףpI|oe`=җX@gGˆ. 38%>!|Du0-\E|bOlhS`/8Xoڼ @)Rxz65v+pMX* Z^hPVQz_!J=oݿuljtS_R8zr>oyf^h>ۢͨ1\:$b+ 8cx'y>DZclڴ 2ʕsF֍;姥*{8KӲ{9r{RO3$몈 ew puW]_@dŰbAfaLOO]'~:UuW 0u}>CթSU9羮wObu) ƢSqC#}1M,AR$$Z+vO{jݶ㚞M)V$Y%ARS-󲛯C{LMj0?wAE_,p_n?w 0W$;wIϻ ۳֚ʥw'c~ok1HV<` $GǦf6]ߞu@ELDRJԪU2RfMӥMHjBR%Rs ub G8+Wcudy[oo`p*&?1l; 2 @IA^t)fPNp"Mٰf+ׯǟY#:wи\6贷|twg@J{?G*\!+g sh~q 4-x 2;D8_4 Ϟy q \(( 3nRDx2c)1QB;K[zkjKO\((z^:[JAO[lgWv$1:8𯮿j7ݲʵ=}'8pt%IJOo/CCqċ9X,PE(,?;ÿ;>u $%%(x/g:Ӎ:8[dS|*߿tQDI)֔ezUVvCѢRTh!9 ?`CRx4MRN122M7B\?[<{=\uM09$Z#gkm9əNJG;_zthѝ{WT.T 3|(9m0Ug?;Mß+ϲvgXs_ϟv/kVkxյ6Sez,2pJaΨg觵,<}5Vfp?g O<(GeռoDk}MS)E7*e-Q&j`ǎy|N8dV &ӚHkJJ8M.rˉLN,Ve_ym;+W|Rb;. WoZG-֮]C3VňhP."$=%̵.p. 0hHXc{Kyљaef[Vz[huPLX0xܰk1Vį_G{! ^qQVQo`ۥne Jtqǩ :$I9ujRr-p/??15= 7UjUf4ixey;97!)m,NRouٴfX߾;j?sǀm$jϳ=gBBtaN@C;C\gg$?W< gw<3s*p_ęRϜ. stY?e'3ц3i٤Dي9l^k3O tΓ'qLvqzOɂ܆/s)ņZkGrW߽~j1Sp$v)bΛ`CՔg@H `W R+k:i{Rr7íFOo/Ip)<c)TisZHHbo;u=瞤o7cGfN/?-9"kIB%:C+ƿPCw7(D"޿|]7ɇزe G[ 4z+VS/yEd{gdhFz=YvsODdxh~/?!r16>K*j8Gw_{;NJ`%QLTZc٤l)n=R]s 9s!)=ysQ&&Yzwuwr>ϱٝDRq1&δQq |r|,-N3S$ٰfm[l+'7]S4)RQٻ{'33ӨŔVť_|VNTP[[l(!Q14rJ'˸Ho0;@} k]K{i;G<?a~S#:V%B^-zs/$ t5`0rbZDKOBcǸ}O<o(ɉ"LxĥF; w{vR#*ZS*JTaklD -jEsiraNU*X1 7D7IyxfNnݱ+6Dyc'$iXGy~=dS3c\)x)bRRUDWli}Uٰf* ?8O? Ym6nVV\vEnL vg9EIQh qOܜF<;'ɞz`I\A8| "gZ@{O-8Rs,Kdsxy ^ssiN֊(J12K??ɻ8a/Z _qW83;6_Hb뀋=~d?l?Z,\zA֬^c?֚Wugjk,Y^KO;^w늇z?=5Cر"*JR*%f1Vv7ejfJ) % z.L|h$<9Ί#}Of;y7730 S3t}2'X[d7x$#hwSv?LŖyMS|]9,cHӔ|}VuWR| 3#KSȣt:\iynuo[׭;v\sРع$c2R~s~x1/-EHQ$J+œ[@OkVfty/311-[x+^)x点8)QJ!! C;@o'ɳO;>`RZ$o9,XRAnin|>+_c11>Y?-eN8H)fOwo}ӛ8rX8=$Z2<<'=//pX!pBbA6v-qĕm<^ow]֌p$ކ/sS_qc^g4RH*@ZV+mnrD*Re2s> (A0M8yV;n' nlkشfZɉn`  GOV4Ӆh2ghw֯YuNGXª`n 6novc9nb KPm=w]uwzKQ=+~}06#䯵 ݿ:h;UʬZ9̺UCT}<=zkV7뮻!NcǏe"=t?@FHL#B]2{Aޝ#Ĵ[<|/tPUL̅YI")C'/ j'+n~Mi"-y0ђ[c+Y=\CvN"SsfAEST^rԺ//b"A`f1=tMir5W~Oş 9QuAR37)v!ظ?̾W({ɞl5q[23۠lY`Mj(()GkDE Grj|իVrmc>w}v0?਱YD 1SϼE3G:vsظR׌/>ٽ?[PBf|r0MB~E^lq)?Eg !XlJ\wZbɏ}U/&"ޞ$]:熜㕫F͝7l{Ŏ Z?ɩzPs>E %UG2iБTa#l`׮=۷!ox[fY"+/VFsNkTHg6>:h#};OmZMȳ@+P, /*C#IAZGI; b$CzLǒ4ow:6EyaaJ_{v&&HdׇsFU+F}IRR븅X_m\>gϞ}l߾W1}(}3/#MdxrkrUR!(".ŔjS0jl$)CZAa2!VYΑG`dxnFxO?ͷĕ^OU9:6ʼnSS$6$x欅[a & R1hzF׽U/{wo齇>|n) s `^N t$إXJ_xĽ%yIX<=yh)* ,7kzغ_~mCyPh(SAXk;AORPcYjfvv>c军nf4[m`M*R ~c<V&TDiݴw>N=&8TQH~8c"=H HD0A D{Br! 4@u_/>F\BCAkMO-ڭk'g۶mOL 3:.{V\@K6=B~bg 9μy@:~7|k"Z0ۿkogg\{}8m.=c5]=U@kT\ĚZ)b:7t]$ ĵ*Q=E dIӔ)VZ[ٸq> NsmwZ#O1>9 i5n`jdBy$)<>LFq[kw<7.6[{?Bt_+S̟)/9CMo-r#燞cj9o^d k~6d@Q8%8 d9@WjE?yK>?Nxv )N& h-,:fjRK1Zxdc&$gzn)hOӯڃJA9ߩPx(/(9CXRQ '_Jt􍯿o}}bMYYqQRi(S'//p)ܜ9gahpAXyYb. , .:rMmҟiN"rz֣ !H1~'=|=eڝ.UXHŘoz ?س?|p$))ERV[)3l2lQo4hԪj J Xή) Sn±c]1Ν#_чȦ͓^džh816I $1 cvm}:DeEn{?|-ItL\Vzhw:YNZ% ȃkPU;v8NN0:2lZ󟿏"+Wr5X;-F8t|kԉF81a%8 :FMF՛6nﭖ?>Sӳ2Ec9.#T~ݷ^wPu1:I K9_sSs(J ~(U<8v 󎷿M60=3C9Wx,1#$NR]F4qN#,ɾghCg$XHieE;K kBʐC#ނB(! ݲPt@=G$%T)gp.{^~}c9IZ.񍯸25=u0\43;U+VP +|K.[,/$4:]6~>n3H/Щzk^:Ć5n޾|X).5k{޺qf0!qD\ʡA6^ɆիIA%˲bf/H {YN:λ^ ;~SGra^jz*q|ߜ:,1Xc֑dO?G7YVuܴ_ΰIuC?[=/F$_|bVΈɃu.d(Śޞ֮ઍ++|{4Io-oy+7ld|b155=wᵾ\/r qs=D޿`E/#oƆ]R`TL2s^3|qzwH0:B 29-.D"x p cW޼㷟|`-luc +ǿMo6"rzU+W~,d׮]\~IK/t_ X8yzk?״j=y1Grd^F{T~;sKWm_'RR^V~d(h8)I6l{{WꝬ]z/tfq\ G >ܑ.4UQyNn &{M07W+nT7.rk+G~^C;b3<^-"-q֑68[pODQJXǡ؝Sr͖\qӞg2ˍ7W]Eȑ4 yԸ0OL9R/ʈ\i"մMmz烘 :tޝY"DCdXOb*\q-֌/͙iYP#dRջuE*DfcMrՕ;oZes|kkE/΃^-DnF[ݼ{_y D{sdl,3i-! BOi"M2vUٺa VwgGAJ^2^344DݢlbAC3P4[lAm((yC<=}qZ$4nn)TAQ2RI49]z9^^#ɑ&G [ -gdL.40hBɇ>|vPT(GhuHx +VHRH.G[!/ޡC{Cd(rɼLXIo yb ejЇ*W[H%]8)%qV'ѣS Hr3;3믿%y_bIqa2Rx*EMB?NwR=+)yCGW 3=D[6rjT*ۮ?EO!@qؑ՚RDoOF:IMSBR*EEDZl4(ذa͡CcusXv%O>ȱȌ Uq8YX!PccS6|vE_MN#\%wBriX~ r&^` 9gqq89m\3wx]R=g}GN[]h#]h$|9aa֮#y?~-6;dժUt G#MS@!yyGB)pt7vؽOُTEC>Fxw2Pt"lőBc#]NI(ȋǗI.qƀa}PIg=KN7_3ljx| Sf i:OA1YE@XWcuGOvsNQ:798[_z=$o_WCOY֔Gk&MfMfT%q  j9ij*^p)zA>zA]{=Wm9&@(X!-`ޛGsB+V}qZP,[1 xpb L\x赨\8%%|\.\dDwȅ~O[,=XI 1yH e VX֭B|՛~+oޞ^NN.aȺ0]APWmY`-bxqn]O>|4+.8/.PdRem{(sicCEK2*B,H C"=>A:'VH}Р5wdcSTa3x(y Hn8r{ߙc'Mz"o~m<~װV$95kX{088x!KhI^Ž.y[,}r"?^q; Ù$MSS3ȏGHbQv?7 {yNGJGy+_k?eEEq6?\*[._0Qoh6i;T* X<};'@⽧lh쥧rٽ9~ȸy [=315B NA.L2X>t,Q|yOE \\wy_o /e Y"_R"I/vm&k-q\= vX;ܘ{{M׾WsĮ#LL7:;_kU¼gWm]^Ǐɿnz^W+qh6 URYH^@̧H6AFjPrrw&a{'i&NB}&',:xaeQY>)zd1c)%`!DhDab|!o7Jx̑@,9/87]>t)w߾{ٻo?ob ;a}]猘4e||׿ sBbl [,<$`G~X;ĕYo<_k>}01dbv.X:̰v*֌?Sw?1יtiڔKeJx@ t  rwfZ>#;nv ygw MRA `A9G5Fg*lvu/ ˾r}'B4c><19wփ8#MkGU#sxa動TK^ ]襒(ڷ~ 6¥Kc.jw v` T;)*BYQEm̹ P$^Pu8$]JE #$@;K <2FTx0&EHD,Y127gfDZtҰP(,ƑbkQG>#G`&hPY1:rZb߾}LMM}m"{! HqYΝAq*Be"KS?Nwл/]a6k ixlͯ{_:_!%12ԴGzי7H V *~W`affA*v|{~[ڛ}(ynbP }=5(GJEZk\_k& Iv@O\i};v*11UGIrOfrqT )_sOG[ʡ2Gس:.7r0>1l^gWCQLwva==/Кӱ)"z@+tEJyT1G`"89KYAKt-XfDa!)ZD"Kk*H"' L!8G$|1Vxشz/ob˕}cx1yga cnYq?=SӨHvʗ(s9䅒R\䰖evPfT:/j>|lX3̳G:̰%rgWv >a XGZSVRlFNMRRw qc8y$  Vk,gh>g/mQ2is a Q"E>N]uX0wx(F '0@ 8 A+T #g1ޑHB)4$, : ͯ?%4ዕ?q׼:z뮿[n={-0^t:A`ڵ\|=ZXkɲ%3_2I̗X}ߗS}ClV72]*?w{˱oAmSo|ai-^{&g׿z#;cKTR-3TY6NBVT*qΆ6%Z&&V+ rw31>yw2;Η{zR* X-B~kl^966-ȩXcp60cKޭ -kp j<ZG٤tUZQ;K<\QJc1<8F%M5RBPցh: v~R9= dD$,NEJA/u>%5P '$=[ _V@ek!:B)(g ng~vӚskUIH14Hw8xpnêU+@-$4 6(V*N184ݯWhvk4v_:Kwcцb{d.Ϲ)% 9ٰ"JƵ+X;Kc?uo;ﺋQqRI|L$- )!g">8AT%i]@/_WΒ܆ ΁B#F)9XM`a׹G0֑31s ~Ek[g;C: -12þg{$Qwdz}~~=m3GRYf[-iFRTogNo mIjBOO/wլX'|yy=xnr>c9˒gi"hn ?J)_~a)M*;1<4YVŁ+i"Xb]:T*ѓzO>j7YK7SR2 ɝ:C,-qIwɼ#Gb}8}c)rHP.lX!Rb OjF bH, D:t8R^A $D b$ [B ": |u<0;cU{{[yns*֬]h;1011}}}aP _u똘> /v,.ԩ%& Ăಫ~5|:yǎ?oyknb` !ȭA s} ]>jzeIdSX14U+8:Jl6`έʕRH!hLNNk]˷}[;س䞻oxFîX{OevrC9v^FAING\m+,峟,An6wGeH2wiFx2UB*Ti{ ڟ#Ɵf\O#ȈlxɃŮYl!դCd@uP `uG;.8*y)w( p@=x`E(Qb\KE_ok^=~>3u[j1 Bu 8yL^l%kaub9Q?U ER[og{vfffΛ˫BX˺k勤iJ9rnVV*ZiMo? G/v _ :" ݧg=LOR* glظg֯ƾçV Z{of-Ձc"Rdu\,I|\(zNդV[Xb|+_Z_]%dc }ZktA\UZ浣ǜ<;~T}/7oyIy?dxE0zӘ8>Ѥy"HLb5e*k5T FDy*&!+$ ) Xt%Dޓ#HBI#phh6_dVan85>OO1<4_u#=@,ܐ)MEt͟^>rX D\bu]1B\j333C.71zvX@JMg2|o~{>_^,|psW%D#E) eNAnپ}~gy-W\ɛZks4l| zyF/"+tU'>AA=1:O}QBVCCq uGteDG#5E%d _S0X7mm@ #&HgKJ %Tt<grqM`}+L>`7Mr:O\BP_HW _<4=dmC-EXw<aӦ}qxrc)s ?og>|^X@(Ŕ"j^fn F5J-J9y:a~]?gzz~GP*Jڕ#2>v~ t:^rwʌv;^`X#&QVŏO~O>Si &y Y4#9UkӒ)I^RBq~ႸɼMd-NegR#t`gS J0/KHR %o“I.53(k :mJl|, aS(hHlҌqh%CpuWn+fϾT',ȳ [7 FCCC ~jd *p>46^J22<̦-[e||pw䒷SM;vFR Kҹ@HpiA^f'%Vr8Okzjokrϝ\$8pljZkG!"Vka0" =EE)` RA' ̃%D1 !r& ,D0RbOxxq*@T 6}5 o\{te͚U /8.l6xO'$[ti @N,Ϝ]}lذ(ji:_7:x뮿o|kc|"[ p_0M1)>wsETbKa{ٔ_@b&$~bm54D:gu]AH.+)ek1SD(Kh:ϰh!}p0%!iG1F)J6-E=5"EGIR,%MW)M %xh@[ŘHa A G,4"8PY#lh r/XUgiPA]"`@o_g`xÇ"n18ի}9VߜH07y)PPX*+#gZN$NgPx*c^ԩSx\%`qp/R{_KO2“l=},;6rFKpJSác0|?BPTX1w H1#bժU5C-GeK "Iz)KE<k(-tΚ%+سoϕFpSc"-1b%Is//X@kZQ6[5XCۡM ky*.5>ϲvFnNgvr |_ŵd3AΠb _[uOjDfO'Nm_a x‚PlλKtT$QRuD jޣt\@O'9NJIA\!)] ɽW@cr 4  A,CbOPxo([* .8 EGiTUS ai`n#??G{޻.YufjꢈѩS ϱ{̿<]a@ cn7L~pz}n_15CCCY६E_naA{Oq|?frl%*?b\[ȃFIcC+%rŽBz]9ʖ8:JocVEyVli\jmo㦛ojS7jqCO& Y{AWclso9o ~5y/|A(elX!%5 =b%i&0kdX[ک'1XI r@ WiQ!bɨ)A{O38]¨H܎󴭧5xȭ `J#=% F*^;Gl䃥&)A ->HP!'>y 7@v;t_^yy.Xss,Zh@}H ixIRf~K K~iDZί8_Nhd˖-\y啗xy e./%%@u_O\?~˖ؽFQ}IS驕bHN@P\КRfxxu+W0׋MI²r9];<2NgU:qD8 Z ծ"}COK?03'(#,QH8j%An";1A;LC1 hO=T!Lt5rЦKK.$yf R'-{fG;CYI$y2)OZ6 GPdsD6\\EREsj<#<;5(gERc}6a+@Q/o(Tf5lZ>tOuI^N>|8@ _2mS`Y6z߬0 aCHRyK(2R W-zStRAD"b֔ PUȮM"1q.%. =aF?.8KMXdD jbz$&M29)%e QJSqRw>}`;X 2~q,RyGݏ~Y*[6o jC6?Kp3oSO؞ v;B(O iMj\5WS*i{Yjʺu~^ ^0ľЎ\x}]8W аJ`edyMSTq)CO<c,$M)j pJ>ӆXQ`fKHaYj}7ۡm#|uJUQfREȘ(m! 4@7!ITeJ)*ъI9r~?DJ9*Kzpxu㨕X14O"r%)iAA slDFԔ(s)/҅$+) }PN ExDь7I|5NRJ EUW^yhvڢ[-,)p3ԏ'jԩ4(бc臙zx8CJQ@_d{ؾ};Jk6l܈FFjruI|sR/Bs~犂EŽ?@el$bu7RLrY+[(VԊJʞu:950b(*IkF$ 'miS(iD+':QPML-5Ӱ"fS|.ɬZVlOiڔYcr͘2.*JJzȌG97{t]LK=LRa EHR@YAG)7hL4"<P‘!h8KW#, ; dj@X0*UHT%{B` E NKevvq`a>˕[R\X PVOw.gFCA  0(H@Rc6B4uïb @,!/T {͜S |O?34{{&|$ska"Qry%4:4T5s0R*!C$T)3{Uy$'ibg]X*]Lk { aP I6 CmO9IL\aG3I "%O pXQ2]*Yt+|QCzBPrI],l}'x;vS8vj4ݙiƧ1)`% Y?Osqu/xpe=X 9 J=[\˿DtQmh- ez9+K9N7;S׬cW[[jP`LL?9"}V7y#j=5H7Ll^W-G p*L#QКBx_/jB0;X055\ 5jb3$a:-䖑a6W+gwI26أo߾ >${(2닑,I,s3y_h4y[<Yw[-k<ϑR^:D;Wu?t,g'}AI.XJizY.szKNwz& o$ {i6g @d/T$fuJBIvRuذє)Y&_4I-dQ/H0D<Ӯk 5R䪄s*>S{A^H zp-83XȥAIKb%q\X0c3ʑVx)dPt$G"DRUHk2"lQ@ ¢Sbc  CUA^;Igr Q?KIӜl!+Yzz?Go yz{C5ź?pb3Ŋfn-,vFcrr FUjAY>c9JF M&M̓KVYHs$mh؞Y|ew R jڳi c]!(I%b]L,"a\1QSH ^ZH1QxBу1(XIdtP%.'DѴe3")dX'^ h㎮Pt!%!% @9bka BC;'J!;4IUBd?>F3tl={h6ퟴ!&]a-M@L1X˪a֭^ƍOK.}$ Ë/u!^ easƿsd<5EV9 1sb^1yp0y އ ݿ/:H@!d2"<+-*Vu`fL7=>H!Xk{t-IYF8bH- p%rz%qyNExQ@`Z+fs]A,! u(i!α)Px *IDL>K֌ECBv fUx.FzȻX$U^SA?CT | BS2)RRѫzr6hB-{ ipT!H$QRx:oP9aqRށhZ+M hٺRӕ1rP_irrՕWP./)RJ^b?5 :lЇ[tVbs9vf6i+nZ6Jjy~y XAt⟻-?oNX`:bE"Ux{p-77|Yp9Vy P3 "hu[46$- 3paXP ZO-298q*dVDXn fhHI*J$^be2Z2E$3B+jҢ%TlWl)t£]hI=uJa"H6@ X SK|]NDsbxgIQh(R)Q HkpxaP#/M9GV/׮Yu~av^,a w%#10r$yaV6 ͢?P./[;(ng ${.[.,e_MXb_9;Xbt:&)(PU!b¡.,bEN ߓAO+01X^Yf&M{v2[5 >sG G.%]aXg08$R`tyV 5l0gl,)4Z irޙ)I-Tt7G˳b^D:\ RR"DBk_P*`W x]LOM/c9#KFBVPMLϭ{iF̴"Q\܅~w9*Y\AußVziL*tQU7b̔RJ^V$I& Ȍk(KG0D`{X]*-J8pPdH0;(j^uD" UX{t&G:xO.d 0Bc}PT.G@)R% V3ҤBk¹qVs(.5rG+ϠՄf> .i333|||cieɖXa"˸w$gf)WTn48:9l}ZVqN{5J)s_R^,3|3.P_l$`A9jG&-a\$,ra ryi`ܼY).\(b IecE ],Yz=uN` wQat԰lv9IoҬKm1 +hjHEi`o $Cѱ0dNe /9XK 2PRDsx9KK8)hv6 {2BSPҐ1v9HyA>Dޡ@'hgQ&C{ą=b{0Ea ZG 7'F3ֶڝ$LpZQD ZPQU$&_f kɖZz0j]71_y6^E I_ͧX}( +f>jn^^08+3y9Arlʳ;^|"_B7mFoᶬH?cfg+SRk iJEKV|t:Jgn'z]Dfp=;r1SvTV$D'q7m X5d{ͰG4 3o2ZeCpK2k5 ʚJx"#ʪD$ch9CiJD  .k)$*(ME8Z9|S !%A,,:.l-Rc|GB@ MKPB DxgrbKIKhoɜ#r!R8 @Q =9Goo@`fMV嬪h5HZ0ݵ<ӱ*GhϳY#'duȤH#M緽B#p$@RgoH) aυEЂ|C▽tNwD>'i}~rk}ӯ*z*o ۷,Oh|q$ITKXnQؕ#Jx]|8TC&]P٣Y'eU'6]3I .);\D4dG87' Z%C) zdp*ch A+:AUR!<=6ZK"4Zz*JdyN `+$RA$aA@1P 4P*BB; ("4 d|șXΰBäe֖)EZI h:LkzE4E8R/&HNf A5ʓy5^- (EI8zX$.l8? @?q"PEpT.atDǃ-e“ H@XOdDnn{aAFl͍_6'gfxdr[{bgHٛ9h[jR>MU8Fde,$F?/2Άs苐RwEWJpHX E,N<ؿO~#|{CqTʼ۵g]?0NZQ!1?kCIn>y֣._Phg+RF hJr'Eh .Y({b26yjMÛ'$n󬘆~ R[*sjFq1Jkj"󨿚Zȍ) %:(|3{z\3P"o)iVA+"(Ќuhgp CE)A׿GB8mQ7*cAP+%J:m[!H UէNS>MS</334nFO}x饗عs'B]C / 4F(A6K$_O[FHzE%PWSFKm˘nUv37+U+e#E+=GU\;VoY UI0֑ Xt( R#!vsJyR,\x,w!{yAw,E(5ɐ2@80)A:$q\?H+RN`7oe:MS~w~5۷o1tZyYL1|XGY{CEP(8ZNeN /TM|elh_J8seD0!5+`uL|F:޿;=mk=or FLDâ.P&DH'iac7l;*/r⡇8N`ˬy_HVg|=Vr|C,߿&<&.]Os$F4jVx&+X(&͒ C2`Q0Mʬ`a6*!|D=pL:tFz\P+q*K^r))R.ha=iAjaJd s!mZtd񊄜䧕ȕT]. RG2"THپBEZ*a% $2 i" ΍|T5(HX;Å !sssܹ0Xc|Mre?sUQs=C/s-H<ǞPPrϒ8O<1L7[o=5W< LMMq8羳 '>pE1  /zͨ+F)9<Rnߢ8r8[|~_U.=5^ھQ<y[eBjy')xjãٵ(#x>}B0<ۿ}`236ʿ9.5=zQFFFyE\)ԡ37q*sFƉ6fSσjBURD0yIS: 䢠;>2s1s)tfHYX!J3R+2,YEݵVcpyǮ=x D#hYO[h >!9w+FaFMP%Hd@< rX*w!,vSTLn| +4^B9BH";Ti" R>vq_qg=O=*m(ZʚԅMNP%f視͘;{Я_9=U<ss?G$?#}J"1pI*qpl(0|oտkDW_[nTpwFW5fLQhfC(x![Sv 8 `.[`hLF-<$3%"!i$U@uS.#QzJasXBD |MBJQ0)qfIdHw̙b0V} d:^PЂ9>%"rjQRgk,{Rr@zdJԤEk k?% K5T\JBA*2 HQPybM(kƣ`YlW_%u9v<_8E/M i"KG{y)R )a@r$b8)Qףl_ߏ&dr`5;^c]VD`uWk Mɯ޺u_r]!S\}?(z<7;Y(wf'4MǠ ؾ%spsS13P/e:ɖga'?ӏ ngt>6Fsp1YvH)=pRr_C6 /ܺ b;]b8IT`>֪pQٮJP_0d?'~=zrr1~x^)yϗ V7ȸcii ^swFK۷挂ADBb`HL-nk]?2,3꥔h2vlZdr`Xfe9#\\S ak=a4j3LADEY`bWmb] C*ӠwT(aZQaz1;A1teK(hq2 dx3H^QUx$aЁ$V*bƃtK)I词[D z!TC@TBi$1SNwm5?61}YT<=-[uFJJ2\u9ln0qoۆRy{1|IFy"/#^VAp^ x{j+g:>˽oi ك^3׿N0vg5wzbF.ny;ٿE7M]oe~;1ƮNLzWi2>uffX8=oz￟bL u7[82O v30TxZFgΜ&IQ/;PVdk-vȈg64B(ZAJC)FPClCos `gK6K=z%K()ŝ>NSU lm[ZY,awS̤̯d\Qh­EJ8%SM^ZirrI4yzqG&Us~qY-Y{#IՒ>Mѣ q#^߳?t~GzaڲqhjQ(5ex>_޼sS)W?S/LVm|ǥKjׅYXX7YAvChCjfZK$LaaB$!)L+겄hUh-48LʌTa"隀gHӄԓɐ oIT%`V"vk\&:jPY$TyVAHIxwd8RٞC .ALhB5m+6X/Q΢C iRz"\XjzNbM%Y!W$4CQ9-XhsHr>7YsNG*gO`afdƲlQ[?v̛ucI~$}{9mH(dqE*ŎAұ9{gϞ]{~CCCqMobll;/H!:ZApB@r: +**HI_6޶s'۽ .<0@6m0}|y{|^Hwhh$N?ďm[xy${m{`$7K/Sx*P9K7 XZZ]Wȑ#lڴ~dsH: nZ{ ;JT{6{3:fl(B:" *Jb,q-$c(&S "6B"2/`*ѼT؊*(;K%’D` =P͓p`'5'Vkb9e§LP U~ ( 9 -^*z^[PiB ̭ރTDFE:T"6ƃXk+Z{.]&u:xGnCc9yrq LՖkT=_JTuD%@s͌H)JQ Cݶ $9ZYAR҉c^:zcǏs-[𖷼u$It:.C 9WE p]F\} s'FP<|G_~ַrX$<1"?Os!MY73 no׃S FYYZOL?殻XBiVwlgxS̾z^@[n}ѸpgaÍn .]^SQ]-p~CJk1Mh\zײD h0\J0C#EJI22Hb0D=` Lhd0RR J01e>aB$*^k6{DްbX&˔dD*M0)d*$Ԓx2G.̣s|#o @+@*q>8O*M.PYJ3I^ 6Rgqb`&I_/pC@{l$ Yc2R,$#XYY#Gx'xgHqnvq<*oqkf?WK?vWw-vu>~J"` Ts߲)(Ͽe6)SZ*_W9?y3;IzL1$O*~v@9솜MG_b1S~7ݻsn*qf>?oh_jM=b.^7~ߥqY17yg!Gʈfp:bIJ:Eg"Zpc2ATFИl31;6el2TBx/`%oRzFѲUʅB͵!1\ɍIj(#2!PYV 'ɉ`0%o.uz24w#E2ο<"K l@ ˬ˝g)yCx-gv{&P|}-βΒdg3IH9Wq 92KKz8*5?k9UeLMM1??O~knW_ ZA o4 IT`@Mo2'v鈴};1vj-GI"uU.ӈ"JKKO|g9_zO?Y4ޠJફໞxyW%5%)[U'~o[˶I*&~[\Dm"MSh6^w~~sqС7,,. g=]}x`Bӣ"D)w`vr=ebs(BEvpk<{3$)ItbK- f/}U(4Uӂw8hsI3EN\gMF -=ZY3&%3^) "7<2[x}4-cpƠMB =A Z!ʉǿ-O-k(@QdAQ*¾"sie%wL ("[kͶW1,--HJJf1еHB믵&x-DZ*h@|Evswߏ+荌[ bڅ={?sny|dNϝc{vQ.<؈ImrPflv;زe L[n9 [&'ye^޳'E 2]i \wqٴiz..g=tfkP،gP15zYнSiO{*4((*K2BH83,' )jE%Lb,J8N)h%"4g8IGGb@xBRUR%IQ8[>?-ڙ##( hB"-X9yxfTϭ~e~K# sҡp%PHdZk 4EFS ޽{>|0c㐦<,z_롩i\{<^Py4N:.Hw"G$R(FLf :wŵBPTr cQ2#Ln̡Cصke|jj1==eJ9^(Q 6.*ٳbN\As>4>;f/W2;>9vQrOP̖---!ff7!7"16Gc+ sOz܁(b?{سg]+++={Yn忼̙3g-(|]f6AV3dS0S09 `0XQ8{N 528!H et2I5:Є, C4Cڌ0N>H8$$A@%йnH) CɧހMn\m޼yj{l`-2Mdk1Ik:$ dK#eV\d*RC= @y'bE!J|o ޓeeZ{$sCoN p}rjch0\o\HT?lټO:;d =ggټH½2f?gbrf?}eMuhɓD&3g6N蛈  u_+4wuI917G)"-,fnm7 '0E9ص_ڽtVZ.m)}}f>/]/ X{[lܯsss={;㥿Rdl}6`j~E=\);$FcEZC-%,$-/Y @:.7ZVnspnCseyBu,>.sU>QSbg JIzv0\᭣$/xbu2vidvm74FC_;/j9fYJ\X}{5giV%ku.Zс+GXپasݹG}C+=GN<0qGuoY8wB Um2_ܼ?!$ƹ}Sj2'Zɓ'2>> jtSIJ']*$Z 7dk+Boxs8#灥0! JAO,:ya Es 6S @s6 Xz!J͐DPP`फ़%cEٟL uή4܉PC?#U*}IGj.BdYvC[$Ud~\y?5pjW''٥5?h#7c]4E?mαt6\18ȹ-9yb{۹s <.~3:=clGL644bNbnnC}csӡ.*bdodTe0(QqPƤElkBkjՐRT`erV`&γؕN1V)+MKDg RH .'$Dh̢,edq R<5 ^Bk4I-b%i)e+Xq`kė߇?BgayEk~ ZXM?ؼiL2ŞmB3P,cRt5Wr>$={^wh./:`:5Rkc"J)s8ktP5JքdA|e!yEַrŐ/ ^ _zqN;í?CDmfq9$a޽kNi7$I( ;vw}ϥ2S2d=-naxY2Q(6E`&܋3j^bAY(Y)!P,E^L0zF JZ$uFl!A3ҊMula1TAAH4ciA*4xTKtRN M!ysIMR 3dޒfB <h$pD6#Nj-=JH$O̷-)xKMy,>/v)O ѷG@= ?>1FEdrVyk耵!}.CWc_I\weA w`[>*"("ŋpc/HgIy0Gn𚜰()0/>4o;>:p)<֭|!~87b# ٳ$IM=swv9x j|gwr{r ТbnM.1$zrƄ܌"p)ݸ_5zrjEY"AY 5S88B1,dPREIJHڲI/ Π 3umf[lJcT (m' EQ8z&&5Q(P,GJ>6*$)"VuX밁$P(! G;Cd3HE@S,!90]?֐k;I $~(g.woĎP3u,e)!MXL3.8KzZxsIRpd _5Q'S'@дs3*% 6Ef)JY` Jѳ RnA܏B1\Z6m-׋TVB`^vs8+ t-nY1Lj<2Žz;ã$##,?PӧٝeX^s L=1T<5EP$VKX}g￟_:'lFlME.y뱴Q__o}+'1:)v'Oϑxlq:6V@ykTȞ~ffһA&hVa=U$B8b}B*J>%EW=dhˈ'ǐ `WhgGGqB )˔ d0B M$a@H~rYۘT*PSz  d6QY+T9b@?{$9 9FTSoK:> J3k]}o6z|k~: q; {Ke`P;I@E! $=YBKZVp>(2_|/j([i!Zy\(s=?uxMIZ["^\x8(i͖F]ޱc,1P:}z.X |DKӝ>DW%9cJw# 8ΜJ@Cy2v4).!wȡ^sw1d.qA ʘ CO&!騉HjTDn#, S`'qHY##_y!`  A;߷G}$7Ot:IYQ p@%NQ- O6XBeEH"P+JEH3&! XQ>78wҍTT\F\_|zuDZ $^xB rmxPYup4| k %[vl˧[neR2(ɻ؈a$I7o^cC_/ `۶m4dH&ŧ)ǚmRk^$m)~0'02ZNw{X(˲ @ 8#>k4x[xyyN P,RX`iloZKѸiom U2j[%J)*xߕ#nb[+>cY2kxWZNZ]{!1:‘β29 c_[7؈vΝZh4nj9>̑#GXYYGYC:{7 %y&vu+?ɉ'FlUbzzb#dKKKWE*@ |4;"c@[*@IEi^)15[ejbsdfVĄ`"J1 qA(\( H?B+hd! te)thች Y(QRLHZJQ&R$RsMǒ/,@܈'~G)PR M$ 7 #0 򝽜1ޑ|nn@^q@RuG6;@B"ŋ 3)ߴ7mC37|]Ņx4WGu~ ~R=JZs_Lt9:P P2oK-v ! nuRJ%˥(W-(^G-:WIWrVU^VԘkj~j?:J}e%~;zÏ?vf+u됀E*hu#`ee7 8b 1$or#6ovt:6z+ m*fO<Jw] )%o~?"a|,AQ۸o0DR4㄂I(0IHQs ם"O3^]&ZI=M{~aܟqC la&N~m'5jȈ@l%ځ .`*QLB9eȐ(KCIMeH)VP {CYx@p^TJھ99<4D{az@i .oޱ?|%NOp[򒡕$ů/378t!8X2\J-U G!ɫ'Vzx2^11_c b~vST5@N`}* |ee_q֮W#v4Jp5'qi;X*9 \8};>AFMηhr `&jp%,abbc*VVx?4/^dddd~g_5>я>9r-[pA#^5@>^h er3>Ȍ3;Т`cnI{6Qf3rwwA04tcy)O23&!G8:qj'A9h)P8",U%% ŰF:`v!RbYv qJbdޑxP>CHH"vб+bPy."h9,Cs\f '5odMQujv>#0(;ORHbv3:BC[6k=?*j#c4M=1Z.K(|xDR0g|mKݛFjTtdB *䣀 '/f0 Z~)Ϻ` Xx-׍uPkmٺ;533s)I s"2%V_4^}nAECCCI8026wt:l5*kLرc?>OvyOdYK/ɓ'СClhD! ",yh)F bbN, ’%4gVxm9~0Xίq*aS;9rn3>H>HyB= {:h $CCYZjڠ$> 4S REJG$VYKA(R+V0[P(&%;A(s$y7EoB\WyGfmn#%-%[+P2w"+ {@@9kv/}woټG 5-WH;:ۆy-4m5auhBQ_Xl-] RN-ԋU +9T΋b?BzwuM?ծj*+?v=^jčEtLY#37{/f YW~6XTXdr?OVV)i|9`EkvjM3M7<6{ȂHJW{ m_fB f5L a*GٱA|^Wcfq":ȢeaˏoOPENXRB*"ώBBTb aIk }DO%4o@gYT@$d>_o@k)8C'Ca;HD%s"BGxYHj+:@(HǵSϓ}p^LnBW͡)+xeKbW6< B޹ϥ2ǜ([=9h ivvna5UPv:8^+XV e[nc{ x=Wbxl ޶۷3:6bv{-_Zd}H\V 0<<Z9SO`#ǣl:!Vq)pAo81=vz[ CxEų /H[w~͏C1a&z3w##L6YC:~>C""f~ SH"A\l!X6 2P ]ScYQ%2KzF"AXMAzU\YC3~Đ{)Ai'iE f:zV`Q}GX/hJŀ+ ( : Gs4wA;h@{anl0Z! ENb綱zJ3Pq8l͏ށ(P!jPWW"s\t|+? z};c/bZWj\іsk![yIk5BfxS8}a%*?\YVKnD* ZA9r%RQy z:4IV[csmo6,j7 uD;>=0/ '_߂{pv"qyt5[OU:A%k!+5ZOfWivn9O(9f[?Y֥RL.r~ۏ2Bm7$v8Dwʓ5鎱2R );uPΒ" B?cQ I( dBxI b#)Rk:pƁ%T$aցA"Ł"7F Y!".qul|MH3[--3q K=Ȍm$ONty@LC XbCa<5^8o䀍UK_K=z1m89qsssXkԩSk7 GlxzTB8 r:I`@}k:SErn~ m +mW~VF,gG?Ķp&Xb +Wk_sxH4w,tB@RY[ \5 ZE\"l^VZ1éSЇ>ÇG>mzf6S] e.\L@ @Cjp D  HJp %zKNJ+oW4izY6o|}&g?bN  ڣ4tI|SS\"%&D;;B%g {R .Q& uh] x1Bj=zrG@K}XgPIDy+\+ PJ0WWӌ_y)|Iζw7a1JAcrE4j5F&Ϟ(158ރ-ܾw/{t|׿T~nRp3<𺤽Z!VWa+uVt~j*@k֤b#('ur_gev5 k 5N4%IRLOOSr,.3 L 03[an䁍2J)x ^~e/nyx{ϳ~^}U tرcǚ Ap!TnR Kdƀx(CYPw[ZO"#Hfv_eSe0n1}ƹx /X}>W~NfOPu>`% *Ggpd^0wRRjhQ6?̵)NQi2Bҷ qH$.'Yѐ^ZP=[sHcBaE΀H Te\7pC)#Go. ~"*E?siۇY‰?}md1: oz ?l5so޿/!J]dm,2w:D8<Zslޱm; \N-,Ule0$c,[ӒU)M G{+뀫q20شG Aڽ5OG& @"u$I.CVei QllcX\\d͜>}__~ؼy#pa|A>O~ܹst:KV0fppoxE(YcQi!ha0c7q~zXt Y-x1?Ün8JL^bjc!vlqPc B3I(kFQNʥeZNa`}  ,âf_u ')й $$8^( ^їR(M@Z pHb~o}nٵ$`,O?ۿJ6Z3zKXmTdw+7o&JմYXF@?1V'7 @ÈTwB{'@8hh i4<>.du\1`ۼ=|aYYa ZJ֭[BfyG>GGGB^I|z!'OdU*}}cضMOOW;3͛7u]Ǐf=X,~4D ǎ$c`l`ba-R!"kρV|V1IPވWimǦ1j$;<}#do|Bn Qfw,Y[7HNRy$_9(%qdaK!#h~hEl|W $!n b" Ү ,pʗ5aQW{P_HH('O'9,2klc5^^Ig_ U8Acq|iS}! %}syhix+Ahiŗ^_Ѿ~W!p4+| S=5ȟZ²L VJ\WvvNOS)z &%蒎6JBoo/7G>BRRZ8Nؒ7 5s8ʱco⹋?^?Ykff\.9+VP(T*\tEMϧ>)~7ݻw9qd@jm~Gtci91*Vod3AlLVz%-y;zv۸,܊I%<|NQXQZ&2jzzݶZVxU H'}H#xF`H,#h}O%heB#!񵉄{Bg? aq02l-)2$ R7A76Q8R>`gĚt.ǡG7oew+SB@f?k)L \c7nB@>y\~FhB^ Z7'c  ɮ]߿x<OKWWW2!.@)'NoO'cvzN6lIny 26KK ---{ B XJm6>ϽjzzY֭[ T\,m$UE ZY ,d!4bBFwث.%c~ֹ/anIu֡(領rm?G̭Pw2ycale"X %Z|SHSE@BձBK V:ٳl ,CUF4%Kxס#@jEd Zb` `G-`9m~`p$0"2;fse>L&>07!V& @?8{[>N7܀K%Ȫ~v]EbM:` Ik"| | bij9Nsbrۺ`,4+S3q㾍5TApFBIIZ)HX=003îx#ckײRQ-."(JT*Jm|J޿?;w$H4D"FO3-8 8,X l#'|knniZ[[kV~"󘘘`rrb8?nkff6^.oެΗXS.=/\.GRj"+'UP1i,aPh2͓ +2%킎|6e! d{jJRϯ 66ZC,(2yNj.%*HjNIkCXkiE{HV(!p5h%PJ` ؁1Fpp`!{E4129EZ6Vc>?uƏW.[Ղ'l3^^U+)R(7n 1W&"(8f?A>1M^Bs>D|eaILhbyV-2w,ՃJtd0UT!s;=@u kd, UXubssaS.q x<pߕqB(In*FUZGcvBP1@76MK@AXxʟ o[E)R lBj"j-pCAxyMVu*ItMٲD,Ʈunog݊ɡ!'gQX' %}+WlmmꫯK.aiiZys#@Jl@ߨ1J-?i 5hT덋Rb1<#P ߘ1ERao($Llׇ82>4# jrLV{eQ)j5.R֮],@|u|Tx!^|a₢\THFQ ՍLM'q]\6G6׆W\fnnt:M__;4DzNP Hk y7{&K.i¥gJ))nVc^ݚ $m9C5;i#pPJplA(l$T 00V5z1"K 6"*݇3SFϣ=7HPo#]VĖvXH/gk..WR ; Ut ${_aua!Rmֆ( j"tt"L'H-BDƸ8B uRHI\H۫W!Eyfv{mlՊ^Pkրz Jُeq&LNim'y A0N o#}VgCމN@]Le9`Z_ՙ շ"8Hc[S ,8$-&r%' nm}sd2 2|c-.G+ fW_C^Aҋy?C3)D 5>>l%;ײ,5k֐JwfttZv޶G\رc }O$jw@e@/%Z=WaSm3eFJbK;M$ eP3ী*݇i[KN3`ʨ%j$^SshG`/.Kl_ 2XJ#Y Zd(uI :Q=P}0ʄ HaRFnD$$-ZXxBHjCLt8/jf.WmQTxav̿ZbeZ,2oYO61r, 8]HCRZR(;ikk#GR6M.ʹV+3o/{8>RJ(]B FL_ߙ|/ucѱY~B |{MLLPǶmfgg?c{wXT zzz?~=Y\\Dk}Zc7d>~jj'NɊ+ޓYD"A\~w\-_ B52 \p<(:$}pT+H’iB @̗"2}2*'(Q8H+ !T4vle 0n9 JA`7bm0&T_7A,hv?ATDpP # F@#&P5HVxRZd2kF΂mГ6m}Hy[#гe+%YVyxE 6:8sft.Ԥ@ |Y+O3{8UVb^)  rAw~5}}M.@Zf;d \.S*EGa Soz*"^Gzh *Q6t7__/׷$ccsDrgWZennvr<g__J^333gggϨu0::J\>ȏ1f{'+NSRv& rdH;2 AyPANUIXf$EM1!1tbLB'=uW.{ <Ţfo+hL T0"Ra."^cB _KGGe"Q!_/U3P ЂG!F**}HFfBo69aE-$[k|/? -|KC<\ϤyexLW$zZZX~=XsQ*}vv5>z%fggQJ100T*W ^w*d6M3UVom'GKKoe <$CCC<,,,㵵Ļ/Uשjtvv6'Zkz-V\LΔP5Zi6lxOT*1ݵ]|% Az B$UW!j>=AW$P jZ1>RQGhhcO.K>:߆S1 RRiZ9mh)kA粻HwBӘWa`i"nC` xeTJ&tհ1 `8>toL& !B LLI4M8:Jɐc~sJx*S()xQȤ!G#Y]u7\}5%Nom%nVK-)J,,,P($ׂ_l_#kmf埩?./O|NujZdK.~`q'jFV^r }+VD$(U*u&''j/2::(\ !C#K,.)\ Hl@V؀2ycbqsXbnnGyBC^vʪU1IR|> sss+LNN2??ϦMΒ*N8A"`ŊBZczW@:|G05)!'*Jf2`l">S,IӴwtRR*effBL Q(XXX8kA \g#jjBňG#( (@5P.,fq,W׭7mCHg6_ ohn9NH,W*#Z//oo}[o'KR?2Sqq(jbcH#hA0f?F'x~}O=O> rьO[OʼnSSSrӘ>s=Ǟ={1Z6GOKkM^!??===g7099d+f{6A"xwzJ 7X @-b+@ jEce:<;Y6*Ix 7%9rajnG,1V?ՆUFb6VްRGi#qkE2arM6TlDiNbh a%hL*hн/$i_;lr/D©@A250QVD@)\eђJ/*ru:y.id|821ɇ&H&Ivtpfll0R)<|ٶM2c {sz#" සz9 7o67,^o'8~3Xΐ4)'Lv*Q*1f vwr9]zi}..FZZh6(jāZjڼxLJ>!Z6@B(IHujrǩVxGb0D8lͫh1̀y&G}䓳$S馍MwJ:4_Eju,/  vu]GOOsss1tMy' hC߻|>O[[rq֬^Z /077g?ٳB333\3>׻N|@ MֲZ Et|V bIt) yu i>; bt\"̛0gpW^$R/َϒ.1,:}UĄ4$]JSI$qe`B8, FEU'7JB_!D8&-MTIm4V, R!@J|#L@HAJh(d0(&&Fq 0(}lK 'r_:Z[׀6s9Ӂa>O g KO?+VT*fm"hƤ rc.&O#Mm3UxH$H$ߥ4{pTT`iz&R):::.ٶu+~v`4qx~u K^^c6|;voͿin0 `}][ol)b7 L@[(Pjr= '&R-<`+?ߞї"cc{YXpOtww1m322r_|Bpx衇xꩧN;FOOB@_W_ߏ1~$ɳZ[[(^'x *$Xv-&Av+U435.l(X2g-Hϱsd,3'2_߂"1R~bPtaa*TA"U,eJju2z>[0Ɠql,L%,,!H@k5 ?Q#@* D]0&tBF?<2"ZX -dcЀc N$ [ G BAYW!A?зukIZZC1Vf){JZ `_t|[.3u8|={HE<i zq]c 벰<Ν;٦I0{b >t\lBWW^ 0h^LjgC@tE/|t2RN)9k$[!?_?Q_>-,y^{5rKKK<9cppsB4'ٻ~fqF<~ސ>ʕ+9tKKK?tx.;*ԧkxWYf Z|/~;vpmYByǣC:Iڄ`xP%+,U Dnmߪ"u\U(Rs)eL]SbǐGF`B8TZZXĪ,uXZOfuX@R1.<3` JH42;Jdh]o #F!D5 CG@M & Rm f4&dY QX(4a; =AO|=`{fɶJ$,\k `N)8/2۶mcxxA:::΁Zw=T{ @c."d.q DzԏET4`>,ãW^/gEƕZE)Ymٺir~lf"Ҩ 7-Q,,;Onwhj)yd^a)yuςq@Д1x~[b\zϚ7߼y_^x~Vs'Onx,31B_qK ָP̈GggiP`ƍK|{c\tET*ZZZ۷c 7p+W^JLMB`:>:pO>7N&˶صmX _}w z"f; tw$;ڣ,D<΍7<=w'!P p 7y(hy_4s1!AS}T$\DNuTKR70]X`9[rlf)ۇwg?r=aE5G|ݻw~Z[[=|,a5Tv0obh`ȀYR87 7 `;bd_W@R5}}9b9` o Saor~~_gǎd?kxx`ǎ|oz !xGۿ[nvo244Ν;ٴi'N`||EV^<7pϟUVoR(y9r{Fz+;v`ݼ曬Yc w}ws0P,I&d2~dd2ITjΜ-2Ha1Y +|G(qYb[~P-ytvn9/'MO% N3B3s&#SM3Mdr<XI^FV ;9-2YFb ֻq$‚'cMw'OK aODXa@ǀe|1RbY1p0G L#$JXb  4A#)W,=S8-??㴴K{911Ɇ+8<6ތ}!Q'2rbPeۋkמ_DuI_XRF|T4`y@ < RȀ|g߸]7$9vvQN6g:G2k{4IrsRJQT;w~wNJ.55e(,BH :lqBռu0L?J4eIZq;ʷ5Ly^uf\ %~rG7~뮻G=|_'/f֭w}$ ~y&&&C)ť^o}HR200ݻIBRvZiii4ŗ?ֺImiOIQ4NMK/3Ln`MXKyI;rJ[[Is t5 5S1i:RGl<')%7o&C\_+LVf'ڜ@" @bP\tFxo䓣t$czŻKKWr`C pZy&jO]\q vJ֖>> J%YXX`aaZ[[?3JFGGVXE{{;\uU]v}V^Ϳw'Ng>p[oH$??~ǏsY\\3-iooϲyfM˅~뷚 og۶m\uUl޼OPhd\wu?M.R< uZ/ 0580vS75KYES U@'x+6m1QZqs.vԚt?z@V_DFllB&ܲc)`%d=h'P,ˀg,,Rb @.bTd8xa`PG MDe *jFb1DCQ%/HbB~φ5R!\9d*E)P$q.ݻ+dwgȑ!Vm̊^mmᄀ8])^z%n"''[^r(gʽ-b'Nm4~o1;{#Rש)EeY5Gkְ˸yvW_-fs>y~:)I:Z333C6e``/}K_\9@:bεO<1G.0CQRh ۊ`^gbv}M |՗XZ ۞dƇֲwz`%=={V`~>/b|m%$35Oor4/]{\K}~yd26oW_k뮻HӔJ%zzz,Yoݻ[yGd2/"?0㪫P(կ~Qqy睌Q `zz>ZZZN:2}ݧ8iV?eYz$ĚH*xqҹ"V 3PxQ$JEjr,Mj8A l11UkU7'82A6BA 7ҲK}M7^#?@rnUH(1JT]j`n |!iJc _:P jhER Ӑ BE"A Z,I4/ Q5QD8y` eN;BNLVt'$ڊHrܰfo<^:S!-3mO˲N @ h!,#lcd@"4VQTӜwHRCC.,[|bTb嗳ut 61 MFjEB=cǎGOO5D $)vA#΍"eё*ǎmèKik|'VADk9RUFG([O^b{fSu mO[pX,k鍔1;[dt"myOZ+jyVZE[[_B͉Ȱ3 < wy'k֬iBc4΋nYz5[s=/";w^#`~~)0566__ST_L~)g=x ]]]AJZ|K i$V`d8=P-IB'5%XP&tImae"+*7G11O|8:F3ՙŷp7%=<_֬&35 m4:L VX"@`j*b l0aOu ǀc# Xh!C)#ayF7O2F"-%ehb%BH$*"#VԎE h 3o籢ZyJdK1 aL eu chU0f7w} /^3zHɒZ&1 $ $'_qYڔΗM.l ][4`VNw'9dzbɒ5Q D 1V!(N0zRHp_B! -82D\uM".?"LTD! ҲPR$Vh Ll#P MH(4ZNͰcSU?y_ 6o<ݹ\3jx?ʵ^{яcf^4Qݟh۵ض qY4SjJ{{;LERzKJQP|"J44 y);4Dߏ(Y|P*Qn>qR YR׺I*l/6N$&!amx-WWw]mSRgddGgqiVLR\OS,αl#=\ H$j<ԫT*~_gժLٱc'?E 4).>2˳O_ 6Z<3t ִ'JZeaaןbHZuu֑N+ľ믿{w7xٟ^i&&&&'1??i֚q:;;OmttcIi9qfQq/([Ik0Une4E.$ Q_EB5!jEu:j7AJT(%&rֲO3$ 9p"F_B1 شS{&Pd3OTar&sm9ǺB0x0M?e 4ac#Í_X(c wF !rA@5l-t0" 6o#oIlZ4&hn7"&Ȇ9%@HwWW7lW\% 7ttzsٴi---g=d2{=s"& Vg:O4@rr]VJQ,/X,㏓dԵTXE)f:0==L؄:(;F X5&@z|qPq[%$Ya( Dh%i+~^xy-nof w.m<W^EP {}Y)]cLO_lj?tϱ}aŊb .t GXXb%J DzJVa:Y)5qx>GYMj$!%VYRe-a'ki%bɒmB={DL{ĥ&-MR= " heᘡ2p#;f0#ȟCh,0 Q!u>t:_,Ǒ$ Lqe}˱jժscBX',3i嗓 }"5d2I2l5t$T9{Goo/7t]wRJRL|>Ok>SJ@1 qرu+ہuccou\@[I.|ӟ&211%b Vz]z*~ne߾ /|g>H<VW_{Aggg}6ƨT*9r˿.B_~|o Ἓ//pM7]}q=`67pB>>9mF&annRCVx4L持|zz%6o|Z0;;K.t EI,kZwmX YsX*B)y.uHjY*c/Q-ÂDlq c$X,lqX'$\zL^QhKQt,6dFgq..e W(R AИ' ńb Mp(H dX!Fc F mPB64i{Ϗ1P8$!ʦ;虢rP83W Nmu͛_zY: TGx+-b* m<j(% @a!0NE 1*jJpLh% E)"x EL0Qh"7<4ZqWe1zWbE≰oY BZrW4:lφUr@#q8tk4O>$]vBz{{Or4ƠQPcjjDQZ2==M"8choo?m<}¢{xjzIrDH:(,Nr0yy h ^=ɦ<j"MRUL^qHS:$AKS*3\8<V>& <xu.#x#K`Ydl(jb@"z98ږ|pOj|BcH%,j!BDMX X ثB"rX,6MgˆE*D=tT[˾LzYuˢV\%L8KKKd2&@ އ60lN ej!iv 377?LMmXK[H2l~)6Ƕ8>1ͽ1:ڑ5WVS .A5 @OJhS_>vQ okkkN.b6mD>;\r%qܰ'ӦYp]7>svqmKKK!.X;SaL˩NZƏəRy<5\?so!FWB,IS-mK8'X d;Gz. `~Tj5a%t oh/%gB@QhC xuFI([6 cA: 2RƉȆ(ѐ_"(HP5!6:RBHlRhzg$u,|c +V"v$Nt"ҒX"M>@Hn`@!k=-N$޽Ҭ,@h@cǚGeqq/+Ww^I@sжmeaIIT^Qy[ֲ%T-\6Kk]'~~wnBM)Օe۶^2RemryE#XQ#0 /3uXS|#9.h-Wglll6Ggge/|ff`OW+Ran~ 2c[i|} 쳓7eͦ rmr| . hmmexl۶{O Βdd2M^RiXOJ6k``#Je|gÆ |gmooGk@'?NRaŊ'O>$s7sq:Z-[7&'.ln&g݋d ]+x2GXE{iê:ϯdBvF"5Cm^RL}||T&0.$Ki-{,bN26$5_B.kW'X*XGKP%0Z02 66$eQ¦(Kh6`i0"0Bhh #SIH󅠮41XHVX/31YB#a_N(B6Z4ULJdqki l +#*pҗݻOSR$u!FnyQ hol|EL&T*uDBJ *JHR}JQm{ƘcڶrtJ:<?lE Iˍޏ@&gU\t,cc\}ux<"5Ç}^}L0/x$B#'n3I>ğ?nz{㹋Tǁ5H;^Űϧh{$z;19^8w~Ts#k״`ىwyℾb_rJzzzظq#z͛7sגdذaINZYP<?mGd癘R)>5ߴisss\|gUkj5m. J%OOO}A&&&Ge֭o6Lr4 \vkl 8^'S } hIJ#.8O|h ןm.MW1=i0Կpj_.:E4"=d*뗮 KXhTkjz}?c1!1Amu\V*=_q` m BJl)q@:TebM̒WI6! Hi6lcB>!V>"_E3QՎ~$:,'a N`YE6W+| nYHˆDB\v5q׻Iϗ\333~ƍ9v۷ogͼK388H{{{yH xQ*)JԪU\ϣy6 @di%dSfo5ţG~闚~%b6oP(OnȑixBjd?]c7/6&ZOpЋ\{fzh|:;30wv1tss:;ǹ5h ew}K-;=3-Ljb36۪T*LOOJhoo 8?p%j{RVټy3j56oLXdvvݻwN_o5xNԛͤӤIJ VyhH$q2h6r/2cq 7JD۶##>%A)XHRfii'džFVb1bY\[[$O  /[#6r.A2T*QTH$d2S|d5K%z{zH&b1֮]Kkk+mSո[yGꪫx1BceڶڵoCd֭C%NTM3?_"4j};0O<I$:;8pZmQ,k )R| |<GGb+ Oz$S,ԧ1F!nDgiia֮]K:f֭|_M^X8|0M谧紞VHu]fgg8iltJl۶_~s5 b,8Icj#u*ABWWzκuT*tvv_ή]ikkc~~X,ی~+7UΘijJAa7`.f6K RO'Ȍ%MZO8 N;$L_ը9 ۑd.# 6:*5jHo$C(n[G0z`F)RB"%(V-m谊FE_m ,W*Ѿ"ЂtB*?J,:,MVh&*O 0mD}yA@=Pttvr}*ǎX,y? ,SSSLMMuVzzz?SsanZZZ(ˤi1MVJRR{.knm͛) tuua#TU9T*mK/_APhAIټW=8[8WRȑnK-֖`|XY=LLbaaǑWV*p QkoP**۝}S@OX.xG>s5pqvvbzz}k,..ruտY Jhmm=#Ja?kvDa9rJ( Eb3nl>OVC)E&}c \uq뭷b6W_}5?֮]K&axx9WP.1e@Ą 0,Ւ7~} 7ܰ.B Ǐi&%fi?wLk|;۷۶yٵkB* qֆyNW*.by<ȶm{L&Ӝow]uy^S6Ϋ+KC2wiiI!:;;r 7[dﯤ30za aaUVzo$@^@I sYKć'=tr[x-c"VRh`K+ ZK aYj"=e)%QgXJa| +xljԃD$`B "翚 )"Q!Dd=cB>= 8 r*k βc?F @KK \rI3Am^goVcdd{.#Jw^lقmT*V\ɺuRW.jE֮]|E!H "E#GzfR8t۶m>WZrttt4GeY|[ߢV[oqWUd8O?MWW_|1RJ8W\qlLMM/}+W~uh~Hj<g@aL5I8ĬvDh!+evvGҝH.Y?E #HUMS l_/=RNlhC~JLLPY &9jPtfh`0+뀜Q$D!Dz[ؑdu@]H!i A%0T5 C/Gǐ I50 #+T$$YP#t,&u A w #>gěWz )+$2Z@?FT͛7ׇ뺴$ jJGGܹO?4L_~br(J7]t㴵4===!<$S"c X{K/y, xyXy&,%Sh= d2(5ͷo!-{9kzşWЭ_LkKK3 8|`\;~_SƄlPk?yI$Xl6˖-[_5&&&Khmm; jll$bcccs=|Cbdd.6l}{WWٺu+W\֭[p]w/mƆ gCc* d33.]Qfz%2@NJSJViM r[H)E5 3z?;ޮ9Z^{d˲^6B7 /$zss%7y7Rn\dIVG:֜1:%ރng7~{ mƬ\Dax U*3,mC\[#5UƬ(TMX_,w܁RN|AmFXdvv3;;ۘ\atww1B7_WQ(UVC__V,X(E]W\$5a)rVN*۶Mm|`%x';vs^&7(R,gE\pa0|<֭]KߓfV-KV~>ov={`ݺuy;<75bHǬ]9 UJK6e``odؼy3ַ8v7o>y+"Ϯ]WH(Xx1? }v9BWWKV?=z['WuYTr1(bN7E.Zlc6$ 䝗MTN,'Γ"5 /ItHѕ: ԁW4(qԜ{Z)kЖ(ш߹>7)b =Q+(4HJFO<"e2s? ]pR~y.х3ᗪԝ>k׮o~3/_NETU֯_C=Ē%KghhnFFFhkk#"j5P*brrZƢE w}7===Y#Gprg3==ŋNiu':_Q.PD#+QlGu4 :%ذoǸ^,^wl;^D׉}Ìdx\|jj9b dhhÇsꪫ+ַEO$ k>S^Htq=r?vcL6LRG!J1=F1- RzM61 a%5GArG\ep|bctPvt)ykϓW(JQT$_3ʓN) pIB6 B7: EE` 9)SU4FTOQQq 5퓷8ԿqҸ 9]fQ8PUv|JG$Xg=SXryD6Xuι`j|dY"[!jReXbr6l׾5FFFX~}oit+|B@=z!1_ױ֞/pqϟO__Ga… ra.b.\Ȏ;QRv/ ,^' gڐO|*;>r2GY025uNvӳ>&"+6l@GG'bΝ\s5Oiw؏?NkkIA\A֯_5Xr%x;ضm[z-pnvw>dtt 6ۿ,]]v122UW]EExvmz댍.%sKU;:*@i9 [X}Z(ʎ.U%Z 6ESK*Md+meW-Ǚ55j㳔;ٸpA™2Agz4QESd $&/i<>-+A y$UȧמyB'1Z(QHc;*EMy3eM؇jj}-bIR^A H]WwI`D!Σk*e'}j.B&'jo'/\ WKfffKx^͛I3xcX,r=|[7 4SUزe ---e /{۶mcy睬X8ٲe W^yYyY4--\~|~\Ao_7 ۀ,_Q7dI j\poѣ}\~\tEG6l·n}.(]wŷ-/_NرQf?7V/|3߿$$o~3Vb۶m,[%Kp!믿B]z߁3U'R<7l&N& Hl %;Tָ@Z\v5ȡ*1L/oemmd5je`B–*ozӛW,X@P I֯_t}Irlܸ ZZQJ(C2\w":vx9HgκFlx?㴷H??LƆ>j(u{7QJq5א$ ^{3~>OsQ6mt+ZRᦛn .[rׯgڵK=&5;q8 vvlbu^CtA!fBB!YJW3%78vn >ªm \|1fd^ };nʶm8x{8xkmύ[rS"?8<|_ovmcظqcÉ067!((a]Vk//cՒ'aii "Qc *-jj]сf=Д#WZGG*1v|Zz#|-sdq$N~!oJ"Qʯq [giQ5c/I$!X0:$T?"M8,USWTa#Β*A)M޵3X|jNQu ֭Y"Q5͌OY'& IXJ7KrAcf?m(,_K{n6ngYv-X,ruqeqy$I?|0}tttpw4L,X>ȦMhmm6@O?-b)@_>.6_NggNj5dYV\`_ve3^ٳj͛~fڵ]wnݻO|M{{;W]u ._%7|3gpp׳x׭[;7񶷽͛7u3=G!ʒ33|W}\턙qIrtNg~KD bݯoAj1o>LIjYA[%%]TW70Avh|.d c4a&r (Puf ~8&SS>Pk^)"l9qjw2ZI }#Oěלo-  ȈtHC Elnf͛GWWL HuY? C/Z8Dԋ<ɘ:kײqSr)֮]ׅ S?m;' ` yf7AN ?,_|nGy(^z)V:u,XooS'\""*2`/74 rK ons5Խm!;!ʏCOtrjt!0Z6@LeSԺyGYO`5m$me/ W @_˘5䌡Xuq~N%D:GZ<6 `P: ZBx9$u !ct*XQ(GyXk9DtxkhbQ~!~C@Rga!h[6+ANZ c ;wk/\Nn { c1<lx= 뮣)jlذe˖=ul޼M61==MGG˦7"})k(-@E =p)?J|';zv\:ȮwqN0q4a +\Dr:DwJg#$c$6BI,ô%H)ZabX&R^uω"p +{爭AEњ8HAs3:G䌇qX' O>T(Лo=8%NIZ (_(*I)Ex aw}͋˥l6˞={"I I]6m>ʣ>ʶmXd Gaɒ%,[GyR\@Tbff`23 O;T:ܶmdzz Pfgg_ކ_*>яO~:;wr7c h^aHTUfgggjj-[P*Xz5~Yb) :*7==M'\ L&sؓkodk(qX7VryLQ9ڥ/bM0Y"A |Q؁U)\#x(lBoӫPfOo!tnGE5}-&!'ވNs(|_³8Jst`%c &H* 6 =팇T]$wԩK:z?XTo3=4~$`D{Q(*uKΝjxmXk_$3jb8b8pl6_ncccy-ZݻqJݻM6q1664\뮣Çf9ٷoiau^ ZE?+$cǎqF@9ɜ2.Y??$pQ* vGe\p ;㱱12LNNr!n݊ oxbѣ,\9C>S Γr"b+uy0qZ)Kx'n9N;Y,DT+ Ŷ՘~f^a/eܻ5Q[Rjnt ЙPVBY)1輜D(Ȧ>\"f-NXPsD!8'dů@I5F"p(Hɂ&% ]Si.CN@ՉK_h8M\;FFRtÉP_r1\ve|ccl۶;v000@ww7_~9Gظq#}k?44Dϩؙ":u!)nty{yd6h0asiY_u y2.$5[ڙxB폍:ai #,o0:$xܬK5 ꄚRw3EP KvckHQ 8Qb 8F+8P.AYV iҭ7E9Gĉb@R _s"xSu@B;znGQ#9s oh|x.G/R0110 xpd[j .$p5

>RZ͛7?#?j}}}/տ'IJ$$|Ua>FFfzmY9q.E]9gKfiIB*35\k+!r-{$kg)ѳfDcS BDifV0f ("#QsCJSE`-9E(UMxl5DX (x72h I0Ρ'wkD&H8}E'9M =SX^5E1aݻYt)r9ٶm\p/fllֵo><\a 4>>ʕ+)J[0 ZsN,qxxdn6رŋ7 Q$agf=OtrbmcA%f<3Bв1.[1>KmI>|AHUЂz %e@1?֚HlsG^kfFEG9:FؘP)hD&&dtVl(:ZK8kjQ~]t; * Jz>qĩ=Mن@)ܟrэTc񅀟+8穫|f8~k˗\.311AZe֭l޼I9묳ؿCU.jElx333|tj9ik r9r0o޼gJ¡CN|>OO򖷼Oi~O}S?#7ؿ?wyi_.e޼y/+3NE)sMK[=?5otsKr æhȞ2_ӊo%:0nQSe;f5(=FmȔ<HȨVXCUfjLw( Z/ d-g,IR*M"c`0tlXh&΢9z `%-^ZZ+1nUtE 8 *H'鮭a~[y{.Ӌ7oAjժFwXr%ڵ]ǔJ%,YB__ַꪫ255*K۽dq|Xc) lڴk}؏rA|Cdb8p'aȻn>l.bZ[[O\wu=R!{1Al5RȺi$R &x;xۋ\샫e)YYl`2K[[7r0f5)dfYv)PdG l",1VЮCƔ`;A0aU~nJ@92$1cIHDS:X/[u@ɼ1>Z萒h88lCwJ}g:k7M.~cAuFA(Nw@)FGG_<86.FEkk+9>Ν;Yz5ZZFoo/GGd۷7ߎJ>s/fO HN}/y{._fRx5\s5\\wu,^^,3LOwljGz9'T3BTPd.gK0̳2c .pc4 tUFvmIls, 09vP % 1DI<^oF lJ4`UD4 _4*@k6I@hJPp 5iV, Q8`m*k!!HҋRmkiw}4GP{FXm˭~j5/_=Ç>!xVZ eJVj2vbݺusNs١pu9 xAЖZ\^?o{iL̰lٲ4:SbYvJoxxyǵ^{ʢ7c8o1.dSΒ9fi)F ZcY&2 $ +,S8b* ]B0^% V,3)mJC(B xZ x;Tg *{( PV`ID/ $IpƠFcP'І!t0֏PEi&hI/,  xN"XTzXΧ]zES5 DX~}r,u$ /_0hkkcɒ%cX`ଳjfggzSż;G.IJJ dE}}}8pcǎ1袋'>UXt)K.}}1;v Fqa* A1RWfʇ9M崬?A}Ⲁ0J"qR1PpԈy2Hj(gBڔ# =RMrb<ʷ$ g $TЄZړB/~ޞTꀐvƐ؂WfCJ9B\p::Mo9cO(b?3R8~mA' #~8Ѹ42ql&j^䞯Pw6]\HYxqc}X,>$|+Fa,^Dj#G ͛ysq ?!o|\fdd)_Ct+:M33bd;hɇQZ'h0DL+I+U 1 Si,ġbXˬ}:$bx&s̘V PV!00$XqPEXkPmT9k:U3r)~́: ~-9t$ AY!tlqKjWTDבj4j/sw9眓 J5 '7#']l]jgg&Fww7jz/:tW:i̎UQ*S4Rhڨ2 6]el7]q(;M>RDREgB%ڈh2L2H'Iъز7#Q6*BE,ukYqΓ8 iA#5ł K?W lV癢*r`tж(FTbJ\֎ $-YƳ3h#TPPA"j8`IA0 V3"+X8j2&BA)ZFEsV '9`DZ2]NdUk)PPAM|B༙ONiDi(Rdu@Ξ:߽[N G,^5,B #_4OTJa]z,ΰ8~x3͟1+E^Yt)ba$9R396ZfggYtiSF9BgęV0k[i*RJrPfTfL5gsYR+N(ڈhH$ !L+CQ9j.DU!:j"A"!=N$^J#Za4&^m)! |R%r7!rQF)#Y'wM_f+[mƳ,\U$I26H-NF(')OqxM(P +B2 tlP#+/|T(QRMNe(5tk%TC(gP!!= 8RX @(`E% < 2UC,tߦkz,Nt` ɟn(MM8e|ΡKQQH3?Mo~`y96x& 4̋q\kf@ t"8Pj#&Q0Y\kL G)pcT9ea; 1L@Va'rjB YʢUN(9p V(hbGCNWDMqJ; 4tfSbC~J :qx--ib7g+oIzZ3(!p /$N4WˢQzB?>ȏZڨTJf˕)b~I<wCJ_S{Anfwћ8\ AUjʠIru'!GH@Y2@r"8`s8=KgkpAD\dAό㒘0 GL pQ3eh EFh*e"^nWN%w-r6]B r/[JA9@PMm82^w h+Y#Dcģb|TؔQN8Fhm/hל:x[~(\*fY?k%/^K%я<͈491>jp707-'v,p?3͋~!њQ] eh⤝\@%(6$l! Ԣ,.̠k"p@(y>TT(q' BZd%-zEVXkA]X\/~3%D$IrGm?z07mn|ZB.e?S>Wq~ͷCϒs7emBLbdzz֟ͺo2ryh ӕ KTMc8*%0H#f(ryykHADUePAdq#yHHe4 $X |=@tϡ6"(Ⱥw:r@6{@ >q&Y?WYįY9Ac#B}"u4=aMr^:8T~i\8;pϞ=ӏ4E`hq>ff.O|&EQfNuAV}]= foƳ솔"+KAVo~5U?^.]ؑ"&׍mdzTေZPf6#,Ah 6BjUjh(G$ XWeg$[>y("=iœA:R8qD@@P+U m&A>9IcA }EeE3!ho(G>x@$5):2O}ٲe' `5Y!'Q.G jbLLjqh63j׿~k7Ne'N 6OZZ1Jr= xw-\\\IV1nF 1eRa>UC҂+viRVHtIa$$ȴ!A!$ "R9(bkHtDi"@uQj+Nh@akݻd@_" ]|nT>JW3 o@-V¤Y"8 +).{E\<L<#+)ıaN~d%@Sy;ʆ_Ϣe c IRDD7f<ۘ<28%箹hzeM? ӳL?M)~pk7bȮHT!Npd}a*MJ'-tFo)ZRA9D QₘU Xb[DF18EQ^9u,m0ZaB$iH'ZyOK8CMVXG\O允Z!kc"TD4[" $@ Q ڂb8$ h*>>̛sLOMКϲEwl_Ӭ^V*x÷>urk>"zY?m-ard0ixVDw-l/KKFsm\_fUݷs|;9Թlq;h[8`+Qr =ꌹkBPC#0U:aF9_8W*.'hY5 Eu @|򮁇2N&M,8UEz(_DDOt'RȻ Z]qsV+d3Yu ǎ` Ě=+m-Yda'_L6 [z{Uo|'Yb5PcRva|\w(5Z3m(%G :>r᱑;.:wyUj%N ӓ=L6e_Y] G mwryhA-1TvdžֱMUVd_CڒtOMXkj3TLH l@Y4%44 (:$ $H* ֢qD("P91k P)I լ5BPQu;_wE) ]p~A뗲la/nxR #6^ًډ{?΂ި`Ija kKov|* vx."dhKR;Qh,Z,e`-AaT@,MgJ)!t0B Kap',S?qxE@3:9={luC$ItAxZ)+[syvf\ٛ/ffbԚ}Nk5Z{CRx%9rrِZ':~N6n8ڽc;8u!kShPji|i)-d~ vaM E PY'9DŽ(O<0IXXVʏB@#BBgOb } [ 6!# W$5Tljc֓ -D(E*بOKt{?_W'D^ۿ[-@WA+6B.{L/{c||n/6}3Jiu՞wR{{~o*8V+o5o8p% >NJۘ2xt wp/U1a#l[nJjKjLJHYeȆQӄ\@FE*"U#W "NHҮ@[b4硫Y">Y.gd81 ٺ{rǚG繍#G3(^q-\r%S㌏RT1=m^O.'p|k'xksֆX$\G~IC8!ajE(AE(9uQY",ZjDTPcÉ*3 #GQ9HɀuPJ1:1UKo9r|$|~\4OӀ'M _9Gz:s|wM܄1ǎ ߽.:~7_HR.VƆܶa6}?E3,! C(G·;Xˬ^GK.CYVY>K4%YJ{cmmZ+J5GX L6$K+ ,Ze(8E@*quBb}-K*uMj+SDր$P!'9q%D${ݽޯs4uQOYK8@NA `Dkz.}m[^} "j__jO4>͕;#Cĉadro ' G+߸'w7c5J*m9/&s˶?l=4qF5>;f.g-rFVTgo{_5.}ULǢîSl]I@u JKE EE$#TY D\*A:kZMI4iqPB#sԜ#ƣ"xN4J^yCq9,to^2i0`#؞YDe˗twyG!ݛ˷n. y^}u[ >uDa%}mgjvf߲cJ?Pa^yЛ}ݏK7]m?vOnZr<0C☱Af-\ƛ^~|nܬ]F"Zl똵% QZhF@`1XA(2 "TMm--  㜷0hT [|a=?_Px>V3ĵJF6 Y2l(rCqlj ZG3x{Rl$zރylte X:$1TrNt׾--oxlav"=Kɰ#:6Wٗ!T%$& AMDEy9"x1 :>|Ku.! Z ib~YBg^!֢ihxeBR΀v1 Y~6"¿|?ȡ&c-#?ٳy?]}w/DQjL& U|wdyz< ?ηo.g8]x%}9o'ǏQT1ֲt~睵("~x{xpؾ%hfB+p:6ѭ[5ÂNZPkUVXL~w?WͩЪ^4{? }]|;Bas|x,\׼52=5I,5U`hl<~hwG0m4rnپw^aW]xJrB||+o~˖}otB߂i?:.ġ0PCHRQWZ'ko0ghYH\LF,:N)s$PP E\PSLS4 5gLhBCΫ <~3A)Rh~m睵)=>5˲)M_Aϟq< _ICb 0* !A;Ey)_u"z5' il 7]z*Da.[/o7OƧ/^vv \ɉ1k/;fi;ٙvwwn\tLMN048H\Xڒa_WQtK.]wtp׶9p8 R̀r%Xuf{k9粻&j#|&E/!h[RLK\!YѢs*jdEw9 8 h4EQ PNw‹+:N倬7$ơJ+ n.Dyt J|1޻}Ciij5w`& <ȝ[4g n|oSq!6Oerrc!Xz10$~t;y 1qrxEL5>5݇~%S,6]Vr5XK-x>s #n輗VM܍GBلD)j4ΒS-("SX2`- T7(?WZ0dR^ _sXåBQ8eWTZ*+X۰~Wl&zth|MXpw$U;7B^k7-Wɩ *+6῾s -ܝS(z;y36)]zlDyoh.쥧#Ͼ#GyxC)J}?SZo+3<6Skseمy#c$2;3E8CWw}qWqם7PK΢}p)-&QHdÉT (`Pvs4Y,@GMvqd#X+ ~g_YW q}1;z) &sܳҟzh_bw>!o^D^i}?·>I'I%WSZ77/IOl{1ѷh?O~?m5j;g5[wiS9@kMEO aE;0^,W7nqV.eѼNc[kb!:{{ yܶnX(rn?ϭ%v":(vBil,XN%Y DS!WVD8!$DEL/io./? –>YG>әSvӿ.]׼">Eĵ L|ٜer~*6^Gv۱c;6:Jv兺R.P(ζ?>t9gـ׽Mo"mȹ65 'w|ė_|7pbenv=8qLOGУ(V>g #ÃkQZ 4ux^'#5{ɲã3 r /W*gǿ$ 7=8QTneՒnngǛ)mvnVvO+^{%k׬ØYD߷n<}ϑɿD(M;\oL68IͥnOot'%9[QuX7s"x~3M-78o<{b4/u*s>1_TPuh9EՋKIoEHRzB)Sݤ"*e7_~w%s3G'DaDKKKQ.Ŗ{ǧf֭\˾Q%wh8Mtݕ\=V<9^ZJ@0ΔQI %bbBȪXI9!ͯ9M4Qj,c(;:CZjbJa9*NaZKITk?Mw|'|PT&h_с-\,Hʼn[nx#Q&C\$К/8{1L#Gc[yGqq%WS(1(`Ţ^Z2螃lR^\K.cHjQRd:p5, ,q}yڴ~cM_=Dbfz`נa jHERD\1':7بK\ԟknp" ˜ԓic';M@ĊSׇ[x-b4䝾J~9~[9R(UNtpαd"<֞9@Z=g 5K^|CF.V9JYupgͲuܵi˫h,C`v1ԂbBɑjk6a{ +0j:'x-q`DJ`EJ "gQXu8cIn?rt"ok;[er|KW38axŮ]|qzZxd灿jof'$?8=%̵8묳ACIjEtAamll{hC89]jLTW^կ&T'gRB=&FaImd$:eNp`p nN?Q,;-L澗9_7{t ܍L %' 89F2Vs 4u\ɻ/sWO"&mI_`h(Ԝ@z!sQi?9;)QS2籪=afj*Rls8}yeYӎ1 e @)$)2,^y ۺ宇w3:=ˏodY:hU*0Kk$@K5$oo&u U RB V k?(QqjBXD1 >#9k7xQnG?Q>6 SLOMs7(1qfYM֒ދdtZ)#s=qlh~o m_*i% $S## h 1)ȈB**:Β/$)([Ey@000H* :눜EQ22~D\r=u-~pbj5)>%LzX߆u4 $I8r0?>J⥫9Yh r8'Z1z*vߺϔ*nPJΜ/]z c}LI;ic]ڭ wr)p8)JasD[! J):sH8 4R|Rʣs{ds&N[EA=72KdID(A-6'7Y8ȓi)M,[>Bul׶qV[!E05hQD"~N8Gd-~ IT@Hy?3@ap$Qu zaF<0v$=;gZC=)ß۞5:Zk_`\tE/kӝ1?wa~G'Xkn% [_O;λf=(Xf-fgJnǸgՁB>7u&iFAj/X֥&sK O@.M)Hy @l xs|81R|Ip Fwzb=a(6h́Uk?PP>YPV>)7y%(ꅁnktOWu  ba P,8Hh<vGAjqm{rTvѼ>RZ+Yʥ"(ٛ/ laA^}ˑc0|4AU L#, %d?I.(6؊9 JPq kՐJ1t%hSi:2䞗c|u|;alBgw7;_oltVLMMp-w)PB\DW_-_Ё&3xa|8tdyYw+$RVP1J)h%t)Bw{qhxtS`L;jI,Z<*>1yRͭ]c}V{v)> Ν\qy8 w''j$@;F8>Twug?iqBk8E5@'V'I gu0it96Jgl*+sF''L'X䤑̉iǜ#9bvckqLZ{N ~/ԩw<<8k%Vuur(CcS$JE!JI$k s.>}oy,\K0xeDP< $'#6t ! YkSzK*gؘYر|~f҅lw,{>ǎc=l<眗= dѼ.Zsv8<}(W X-Nq]w= 篜nR= ~s:[Sg90o#>rn>oN{ ~(dwju$R]P>N%sLQc7qGh%>tuRJgJ}ϞfEc3=2LJ!Pk -W Ewpmrݼ[LZB9V`jbl؄ E˥㘴iE#!(j8X26A  H$H g #Ng䳙m߲?;zϽgǿ+x)? ~g?p:gq[[^X,u}s>ο2֭?NY"65f~otRT}=>}5SQ3XOIn?Dr<==![(~4Ʌ{f/Nw{o4TہSո?{gWU 9Kz%@ ikkAT^lW^zE*]BodLgz=93&03y.k==u'._t E ""kv 3ü|CƹCÅ\RgF~‘> )i͒P:! XO&@–O 2 UN@B%-Ҁ]"Wؚ:A݃:kߛYQز,yXz.0- iaɼJ۬=0Pw 7B8wE auv^8".]zƾ 6MkbI-!ӓ*;]Ǣg:F}p:5 ?R8H$088h$N< ]~88t[^,_ ] 1Y膄]*11$d>)9r*S`H2M,viA<)MhV>"39O$_{2 s8qjhj~?B.Ïo 7mE6ˬ8BF($4M/sl\b% GK[w@hN:T,X0 9ݮX05nG95>r9敐rw*kp@WQqQZișfH'C&A:@uY%V觜V}8 j)pcp8r Ԁ| aSrR@ T,OkԿq@ZFe&MC2- Wh&'PCR"JB4,[uv;k_Y;q!8aDǁN/.rƴ[pv®ݻ1 bq+q3`6IdҙvQqƒL6#k[:Z{&R7lZDz&(rS, EbYx@}>ēhdn]X1g*Q[R]R|pԸ> K8<r21.- u &Ti+o0PohKͻ0 -]_785(--Ƴa%!8NX\fo]?+|:Ç?=)g\pѥXl9H$T*/~6s*Q^B(yqwuO O!8䌺Bf"TEN8}s;zPc͊W]! ӄeIdR)Tw_Xtz<xGwxV(oY g ̯sƑ4HB`@ oN#)h"uwpxӎa\+N\O~ʩ}RL͸+.sXR⬵7Ɠ_ǞЀ͛7c`xkN=3Fq\l6_ȇs)p;m\wnIvݦd%dF3UEi-`[[k0&"aT]'L>8¡ V.^\y|3] Dˊh6pS@Z8 @2 3D?l("h>X`P!!  &5_߱AUʋ`ZlӰ{;`RǞ'>s ֞r24LBuY1 #6~1=Vvl߹D'r::X`vYԨ3MCy nsCE/̢ j׵!_ƺα@N"4Ee^X<^ĢQ|}'.ĦR 0=`9?2hJphLL&OBB&r¯*o )S[Hxn;j* *D҅x|vu)36G* /TVR'6lp;c~isCX|%VZJl6l6 2!0hn)lGcgmNً3֧(w:6‘TIKaUdsLS/hcPTkqV>+c{ !|P\it6ӂ)0 'U(`JRHIHHOO=-*o"X4q`Ylx +O>O<ܬzf&s>\>H  # _0r*CN&ػw6o~ =}X8u;q܊p:3L$ 196;ᴫ;}Ϧ?Tr?!lr/L_'W-[Tu #Hg h**yl.UŪ'@pviDŕXVRul20+, )^0 &̧ :>ÇZ? Ɲ H&Xh n8y͉Xzoß<~lW/n(?֏0 xرsvٰ=grXT: 41Ov"ecz"6s 9ff8V/1&BDkOXZ4%@(aP|q&˒(uLTT`[>l޻q -@Q?+ LZPa*JN藁o o 4_CsgO,_SW.fpOq }ѥ٧CEEfز}7S=׬Che6\m։'?\xѥ(D6E./9TUa۩òrL6u<%v:n5CBu㮺V ̫ 8lz%Far8qr|ÕY?jV@ .:cPd~? E` P 5LNoL*M>Vp .n5Cr ^󇨪jN loڵ߮kv{||lE-;筿- +DT U(rPY-޾֮{fc"Dn~.g\ٷi t(+vaPH 4E0<:4qW_||lF8"4PYr4y8,HRB0 HB[02|q&T)>⺯ pCPTVVo<2-̩`cq5c,5>P)%v܅~[<܈9aɧRv"T8[7m=x9hfOy)]U>G:>ݮㄪ(0"aC0TMEW\9w%h[:jRXE|RQH$&@)M (SBoan]S MiY0 @g}>}♙͔ MR-ˮD DuyRrtΩ#i?c^gihNuqӎQ_Xe@Urơi*jol@؉RqK@S&X>5d Wq~)T:{۾{i` ts?ƹM`saeȦS0- MÚaNo4UYFkNlݶ֝qֿB,Y i!H76pΠ*\v .M;:޳kޠ `bFs2ipl"%hk-*[MHmL4M JNYFˁZ<98b/Z`l 0X"ɔ@LZ4Bzීjw’rtApݎ^\w؆dɒgE} 6P8',S]'z6sNWJ|ꪫqUŲ!I#ò P"Cݦ Nw\i|6BiqUCok:~l{ >ׇf , ́*hZ(hLvl|E'X ~yKWʋ0 @õ} Ν;)8v܍%Wf.~LKb~M)Y-)^uغm'b|70 #_WJV~ʍ3Æ.{7<ݖ^'+N {r}ãM(# c~U|_ j+K Lqnbr2C0: v֎_.W ϋ`&3s5'?u5B8=*s-}#\!^^͛奭&<s޻P3gL`'>*r9ac1?z[?2iY/uKpnRE9"EE{[W,3s*P\䀌ZHs2_({r4f0n#9Ӽ*ɞl5FT!eIac1pQ^]{0ڌ],VuTh<0 )9j"l?lAG|Pgun&,Y+W_aYngSW~x|j5hne ZbOLrC6Bزm+ >tǰ=`ޜr$H~(s )}5U@„"ogأٜyMZ snfƋP4 矸|QVqbA,iP98(s Gy9aqK* d>5ME>/~(6UA.g4MtZwŸ_#r:^TSCڻ\rg@J@U4}.01gҊD"hiiE}c3\|?K! LbKU8:v ChfO}{LjVe!U[ZpBKT`Au6 e,p ͙敔cp;#h!6JTkZBccR;_3vU55s.<>LL*7VQVBIlC85`:i=*5?12VXw<. L,[P pӚv#UƘg\bed"VgC_ff 0 wY]oH&!1$ʋŦ=_zO…|r<~9 !L*ӵ*pIDq?IMS{'SB40MH<=0zE0Y:Ne@$@wBpH)ǑHx^5>O+PW65_0HW5r,Hdn|l >|9bHePypW?w/\.G6lޏȧ6v I~=A%legOgr_/G)lrV9h6=0hK^jc!ӶSL s/;|}KX0E.;$$r55DG6I'>!Y{ .Wj[F=0:"84l_q~ECA_PZVh$ HXkʹAJ TR_t0? Ü ;F%tMa"_ w@ss=GO2ُ2ݛ=yT@$SSW;} ^X0Ji@"G2K,uM4 |o@WO?~#Ⱦ(+NF8ێ5ؾ4?2LKg<4|JMe.f]CdžRn5u3F !3cQ]Sw zg]wKm#F}pU,)CyIEiYd(T5_nP(bQ5,i!ȃO^9l߹iZ,mb|QZd; E'>v(&sf[v:BrZ;5 ~M߮(G !d&w8/Li]7ChE,@IEpB( %-ccŁt6u ;j*J`Zưl 'o.+-TUy ,Dv204@CG4wmq]Sd !p*:b7[;z 8Pn j'MDMU?,LXo޶KUAW|VdY,[ ǻ)k/2t]2BnSy_=,i}Sp>+F$?~v;4M N؇-íG?ҙH)G & \2}`wæCU/r)jӅa{`_S#c(+v`䵧"~I;?;w>, lE"if|Ǐ|bKJpa5h@"DH;xXdj#c,J!2`aŒ_ n'26]AY BN=Tr]mnSf5_*^ܲ{L;v0֝~:FGBiU,Sm݇r9f ?OEN;\vxvΎ{&wZ:*J:Bl9%{p;6LCV{PY恮0|iY7 dSi,8,]|[=q;T?d5tftYjnoBn{v ߓOک,@!a,JaZѶ p5̫.E!D4?&$R{57,]0EN;,+_xdx:wcӦd;4 QSYt6Ƿ5L0V@ێ";R,:q#y{x0|z&rɩhidƎ'6Px%'j*Kr0E 8^q7ޞsz! m C#7h7c6M1 ۏñ]a cAECto.3!lcEq̩**dTUCE<<^Ocã㪫anOÆ :r9lw H\0;6ln3R 8ou2)?2D}{OD BpBio|4}mkm#N²AN;vs=w^w?>Ppjc'n4vzc_i ow葡щ߄"?LI.i!f'gD8}CQqO3͛N]Su(GRK.E|?:l.m۷c7ibarC!o.)Č\Cm=]}Cό'Lg6*Sς6B%Jg#wo F XR*O gim]0 xcG?5x#"&&&ٍ/ b(R$*+ۡṝup,L3x2am=;d0s~PS1e#oKKgOo KJlw<2/:Ő2ԓO ǟnwfX4)`[]Zw5_t.gCow`Ϧi{! !MYEH殾}I_0 ӒO}r˾PKGMEqa/G$q3رcݸ yv;`΃-Me2p]B92+MUaܜLgwτ.)rlᶖQeŮ7`V:/mہ#GG"z-\{$,˜JPVB"@lw'N !` +BΔEpvm]kצwƦ*9Ü~{knx^Q L?PßBQ?Æ2yg"*VBțt.83Zw~XFlj@P΂]} |᷷ߎ/KoE%Duプ} /T?UX< -~o|ZO1!YH6żrHi1\. oUPu |CAn&gUUSiC~aA!cMP4visx<UUqqP8SG4۱A|ϡ aL "PRdGSW`.g~^B!ǚb֞C>\d2Y,^v4^ziN`ǎxp:pU2`l|4zz !o;)%JK˰uˆGz@p11PRJ PZ^prQ', Y/XD|؟ݦ؉Zk !cc=4,\ʟikG00WB!y6Lc?v 6]i$cfo L8x#B~z(?|,i*JhǓ_ң&B^a7LnBdNk֞uE˲;/7PZD2?txĞޗ,)1B!}wԦ+е|q<)%X!G'?Ʀ_z^xjK}k_Ժ?TzdiX$x@pGL!-ӴG|MDU'ļcccؾc'< 1(66*5oMJB;1gFom9`YK_| ʫoB:oBڑə‹NeG7u_B!(mލu]XPS R)yp͵_(~u-o| Md[nò+PQYt* ?Ʀ)8cX= =VB!c%ܹqH 20rc[33oozpi氿cӦa4ИncH !7FXm E~ibl4KRsz<;d'_WW|g{VZ 2_f%~B!Y[KޡQ6(eiD1|#9P[[T*uÁ!zXl9>q'!b?RJ(BԍVx^Jб?B!n}{4M 1^?q0?:c `w}7boaC4)tP]A$D*Fѩ3E öɮk{B!dB[v >5s`5ظttvX,oON=L_I1ueC[ {!xǚS遦J X UUq[nED7PUej=o= @*(g6d ڼic#BYi>Ҿ@8ye:Ȁd2spUEsK~}ۯ/dQ^Qu9s`8gS!cs~'x!rd4Dw/p!e>@gc->ǟ͛ ;1"bN:EddbMg@CGo["#B,qksw~x\* %3i\~8`# Ms"O18,,Y2_'%4DSg_s`E CB95ZbxnpRJ|s_)6oތ`0!?,ZV!ٗ1PUA$MD2,/=B!%R޸` B8*J<Rt !r$;4o2C`6E"(Hgro|@_(=,]t !c Tޡ=DEWsd2H)^2kirhG ݦi-'B!x`p,h]sWau/-RN%{sU 7tXSVB!j m:ۺFPUWdګ g0'Rҭ&BUQ±[7 ΠFqeWT* Bio m4E.kNn B͝_ !n/!2mCm݁xh fg>jj-@!JQDinE4i'g &"QlkBœX2b.B!dV{ je!GBȬY+pӲo{C!Z}R⇌! 1/BȬ,cYP~EB!DŽ,N5@B!J&_R B14@!P@! !B!B( BBB!B!B!P@! !B!B( BBB!B!B!P@!P@! !B!B( BBB!B!B!P@! !r'$2hIENDB`mldemos-0.4.3/MLDemos/icons/bigbrush.png000066400000000000000000000076731172143270300201210ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATx̘_hUdnF6ŚbLjBZiPJ d }AOPJ/%8XElTUMt61iq&馻;Y.l&pa̝o~3CkL)u0`}@x,Ok/.נEQ@֬7yP_r|i_σEz6oDE +bw~l[v`,e)Yem>K%5V E z">*6*yG[ ޘ̛mన˽,ʯ'y `[0 -+rn>ȣe/׸p 0#@2! J*Џ,w(аmT"k8pyqH@ ^)΋@c92 q`ookJaJ2iɼ%wQ ܆WbPVTPkm#R]/gObU@50$mnn>z*OxZh0<~]HW 8IӼkir [.5227BӁ@T*qG@[]2>(N@P<<$h;lV޽B"&tC\͍;*I ۶ {3==9355ukhhڵk٬ڠyWŁ@Oc.l/mjEBbjs0 B!ii1Mr@J* M^,՞{fTccc~\$Jk O+l'sChTuww/huuuNKK|{0ɲ$[Qm^&dRjcee奞mۙ*yWR9< H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxGlaS"ҪMvVQjw2VVmEQ"v7-my<'1̼sޣ03g=zsGX ,^ouF0b0 ߎ rl~9 Ъp XW L-{ L\FW pр?30]Fl~L jãNg:BFu|wϤ8[龶Z 5nM{'`G30Dp_0_=WVbz!w.9YbK]H;CvaK ąnPL ͡"(#jY5 lu wn0CNҴ/u`x yGN!"sZFe#(À!B~T"PpFʧIRcgOsIRh^+_ђLY{}-icIENDB`mldemos-0.4.3/MLDemos/icons/classify.png000066400000000000000000001160141172143270300201170ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F7IDATxw|u5Pzyw;V@ @ig MP:ci3.[$ SL1S,O`)&b)&b)&b)&b)&b)&b)&b)&b)&b)&b)&b)&b)&b)&b)b5SL<xu^S̟SKeƝ@0z@/ :?4$IE"j^Hu.(ǔ4ܨzwԽפ_t{[5QNHy!B |UGBolF| myu.\hcظSPKqYM>IRB{RWxߤl vKc)!*yx$i[Y#>o:NJ0HE.+t4DQu~I\9-|':{\+/3IZ/w#@T́P4BzX ڗVATʶ5JSvAWbAc :q{}X 1gT_@բF0( ~ O n#t4Am,4 LQQWb6W)9<5^P5BUcJۤ r3fA*0f3Dj]-5,> r.f;N|`}^e`O(鈣 Y}28n/JQQ|)Ҿ4w}e5u>#|./nzv`X&[QUMx>]^6~vY2e?K(dQT$EgI"N尢 M#)A˅*aB%4w^u|!ҁ&S;"@(oӘߑKQo'\' *v"]~܅/ CK:!fa@50!4gN@#LN@Z0,lo,گJK$:Qki DB!Xs4(>ڲK~Z,BH4v1O'3dϩiR`݊"DQsq{}˪sEd^2Po8-6RK>mP"kY &: hFx)Q&iFEw^r;I_HD J|*â`8M5l)3fzв Oi"_ 4_m&lb/{lcd!>wlmi!XD,$sBuʣ%" 4_@N| ܻp q1NNѵCIO|nA `.4^jS;ˡAةKRfN@u0 (J] >8<@qF14U8J#|#44<5u2$hBg'oGAY4uK[ D,?hs T[Itm} M@l$_VF qlӔxwVW ;n6!$b$ңK.($1>F]DMC=i0XhJ i+|V r4BrTe=U $J D)"N.ig}',>06@0IF2/<{5yyZ4`—@Me[ :q:-F8V{`Y$ƶ#>6&"'%1rP2K*.&M - A@l#2,HJUa@OmDMR)*HP-cdY&Bf&dhRQ(aQ& ' & Dlj`4SZ.DMً@_C`8cv*k铟UK+8@ (v!+#'&%Y"!5(1>X]a>z,@DOPv534>y @l~ cmD4OF8 ,"E9#R[$}@}>H!4ܔRB4 DF"=@/r=3-GOB!p ()'RU>0P˄ _S=z5ڴikb,^ں44LǖEhWvr3_v5Տk*O:k#:GV@CҲ ZwBkkٮm*.b}D1[۩_h^c (&xE`V6Ŕa1SL0SL0SL0SL0SL0S[y\Pryк<3$/D=昂кA[`U3?5>,;mOS>Ckk1ߚj;KkԖ/w6Ǵ6 ʆvĄm@wD Z|ĝւJ+OKf^y/Wئտ+g Wx+x$qǻZW>ܹ3:a_V:զ̦z?|&?4šyծ+J5ŔH(X+19n@mUކaiߢVP/V ‹DS= 4$of;SMO!^޴U։fʤׁSV:gva53SL((MٵY8Z`1S_$h(-QXB47bL13hPX$#!:SL1*hZ((_ SLzВbFii^>SL1k`_wp 5k0&ZWZ`zKd*bGb)|EGX .]2J-OBpiub _ÈUOOq%͂{Ig?SL1+@k*%+p&bWZ9F5"7S Ehv-)<:uрSL >t5#0h /FHE5b)_eix-\c4L1*@kkWn:0Ŕ^jA!FhգEmL1ŔVآ`D/ ,ܘ)r 6F#w4EQ_^& 0ŔZb Zh􋶘SLiەB xbsFTՋ:kբZ-YR}&h3bJ+@(JE"[tFu ZgVL-W+ݼpe @; :-:@4`-)w /@PX7Z0zi R\ +:pೠѰ ƒ Ι fDaF{-#[ k At\~Eq߾]UÆ_?ںt^II0`TVѣQmJvڔPB|і5?_^^9AyM^ڰߤA-?'{|F.CzZڶeELt8wL1$I"aFhtBs-?Tt];&Oo}68}bbH[o%ЩW/C.?oGRm-+ `dF\1|8lF#lz|'9LW:ndKk HZ !Ns=PлV ZJo_]wu: V_OƎ%0`_;l˖q)11X֧5N#GKU4jJ챱G?⏋9?3 2x;[/z)'XsMx-pKf&,Ѧ jkɗ%>z.\`jr2lp81t(a ƴ3--e#03MW0m:l`dy> 3JZ3zoUb*5>8~\.ˬof_(6)M/_NǧLQhGl۱|[\,.&1;7_?Щ]z&cn*ϟ'1#4SR(?dѣ\68׬tڕCPYI` o'Oro_rnm|۳|lV2{D r>3gRf1I,gv^vȎ&%A} +|L#;%ǢX/Q~UC6.gZU-s ݵBˡ2 $5%$'3dtn.+WB\]s 7YGﻏ'?>mr\?{/0h<4t(ƌαknfMLJB ڷgĺufs᭭exNbSSٷt)wx7ټe S29/a 4x&0tPRl68r92q"7XAםwО=;wۮ M_E3gosq"ӇӥW/ƍ՘ a|3:R 8_)(_bި#'Y ^-fb[N ;AǏܹ|XR´NcH!CxG[oeqZ^E r:>׏;:u"S'6*+IONVN%7WsMrJ ~Q69BiA~~a<̜3](@M<1}:y˗[nWV+C:v$?3f?QAM(DĄB =x6owGy萾]= l0=-[Ёm\W_9dV(@!Da puzU;h:z[1SК/ 8t(Oþ2n{$c()\HSG4R34-ss1v,ٹTGx'MbDž r 7p=+χ<^}/~c$''SWWG^Xl뮣[nZKӇjd ko۶5k֐o UU;~&KFqq$ NݻYzkt\c#;&=⠡H^.\-J`d F񵯒U|k[3OA} N'ǯ^x$]0r/ǧ֤#Gx]6X-.ܻG奥:#Fp Ǐ Xu+۾M.#_yoAt:߿?*{ٳ̝;m⌏WO>IL9v;vqÇJFv~"p݌y$%Amm<4^OI+͞cxG)IIK~i۞ 1bP{]jjj8~uul>0#αWxf<էNѧv+WܾNeҥN+V49J Bכ!ë6Պ( :2h/UhV"'EbFFf/\Hyq1%eFß;)٫28?|lZV]˅AItJUq1F$gt3BY vV^zvfe'-5j8~?;xDEbjk"%$AoIܳk ABye>U<ʭ[!bNM8;xq1? 'cx֯g"{2׮eBpP$%I7 ?VoɦhE!/E0J\9P KLHalnx5VxBCݺqQ:h߹n(j͞MYL ΝtecupM #X,ݽ\s)ffGqD8{6\X_XMVWsk۶L?i71!tBIa!i1cHލ;ɓ))+~\ѣÓOC]V ⳁI zuD$7z4^G1t(7Ġ 0!" !J"-D!-$V >6 C@ISA2co-/}8rGa73IG#G4x0'OP[z:7=KѮ]K2v;eg5H~]giо=ϟGXWVɳgmXp\{-?8rg0kd~0r$~sn:{6׮׋H:y|3U^/;bbĉ|2z4,*S%himƹ"-wEm{j*.]]߾r|ݺ>}xwIH[oe(scc߾Ҩ6n>35@x "b(Ǡu>F` ml4RvtHV`1"#Zyx.!114^ Hߟcbxpq7AYu5y;/6 $&k3k<üt)v;#OGEdTJ4Xu"X`5 \IvEJR# 7.#F6Q\9|l׏'3N˖5yvݝ;虗2IQs&DǬ[?ϛii2}:C7'}%͆f# ]PaEDI"Q8kzߚfR&$P/իEB , gUgq?d1 ػw/~QWDžLn[w55$6.ZNj㊓Ш^-EjJ-!6QѹCbZPucRq#Yvf#];jJKط/J.LlTCuNq}5YקɷCn7 ݻOfcT?Oy橧6n;? Ç9pgΜ3gkNC;wb ;u"!(,4 @  59E1j@=DFh.d=D|ěo*ʼnik$.L´\@6mܧϳA8U[Yjvfx>\Jg$!5? _hŨ\:_&0ԩF ^sP/԰w %EZ VȯޡR~yIXou@ SĄu9basb"jkyV~)a^9+e'%E 4LȽ-,dј1|c,H[2xEN@Aö ʫ(W"bQpyF @Ҙ D9Y ~=?Ku Nߞ=M@୫.xTx1={6yzѽCϟǭRܠFRE%I`u"µ{Pq"{dfC5lnZʊbK\xqNA 5?Oyw:z4} qӽwooF^HŋM!pQ:/ٳ.Xs`tF @1 :N<s~E̞6 122xW)-+cҤI呔F~>TUW3oh|+ ,\47Ԃ@jV1ْ( 8[15NXS߇% 9s s^, Jz5-YBVf& }{~֦ aʔ)q7!dP#:/mZ3 >!3Խ,fhNݽO2bܡjk9bgQ8bb{B̜5Kq}b"͛9qdDck>h-Nkcz`o p=FKSl(t016UYY|jcǎ%%'tۗ@|[INjzCOHyW|t&҂,K @V|5W=C-h*!c[[oy6);ub}^zEXx[\Vŭ[)8|IEi)~I⯿-?^JLdsa %=`끁{|, `UW D^$/@P "Ĭa#hh@m]Ξ[nBU :vjRݻiOٶc`èQ4NyygdP@xj͛՝;YĘzLX#x@eH-Z-+%DG~I623)޳gپ=R.UWG'j/\ Z7]f Z(BM7 ]͆ff*N^biQ+bXٕPx`¡`@0ؔ (b$C@bNvFtNrz:7EPaV:pjk㮻\ӣW/']; G3ZUl!@QF$``/`j44j(ѱ#1>4:cX-&uF{bvII>gzANf.^Ĵ#ٻWGcUr{2gA@6b,rW^{)|j%@ @   $IV~59q' X:wƗ` "iu@zN啕_O~~> ǎqۙ3.\%ϟGPW]29J5|j %$Uڑ?hm6:jEBR@֨Q|VP@qu5S "pPUQAm<{uMƍTVW{50aoAb\wªU\&y|L11_|cּDzu։f#nc۱l{٬5h3@$]C% ~|>w0EqmH0. *ɳg{x\.&Mċoɫ<@·ϳ _s ~;U _s 7^CilQ ABAb/ ھFʴɵ )!3=z /OoX WT;3pbX>#vn[߱#S[YIͫ".Mկjl:8/@~6^M>)aa@ 4 /~O} Uʯj?N^8SУIbPv6֮eE7oΝln6 /UZvrceT?,z@4=a& 4jBz6V-: ( Bv;Ƅ#%%v@+|`ǎڿMǃT&_4^x1?$V2Ánt*0$M== PZS@6X~χ7\4@$Rt=\.2-!C;pC >u.Qܡe qbN:tȝǎqw0z%5Fh hsdl6Fۇ>   6 u]Ek4!,= G jkjYU9shuxE͝L+>pVT`ؑr8He\|<EEʹRzE hnVvy@ j W-  'fZЂ/ nCOc(A\.6o&H n7SgΤaUL8_.^L(bEAGƍ#kAǎoY^^og/MűjLnc\mmmSfP*W3YVxY2~8y^=@odTBQb`(vmwƏg p*|s?޶!ϥ;];uQy3C e{D tzU jh P9Q~3S@1zzM@vxpy4 / xA! QVVg%Eq=/ p?fƍMMQ23YVVٽ8@ꤠh@E px [4s@-4_ojkk٨p~?duu< rw,X8:pg"‰ S~m6jZFghVݎbQW;;) /jS@d| v px=<^; Q~.)SHhߞr Y8jvҌͥMZN g/]ӧѮ̼<^A&v?4U ?HW~>_@/$I1(u֎g (´ipj/^d„ oKAk\TW-#P3S(D x/f {wسmGym[UԣF@5UԚ' GB9,:&AK``s'OkWq6L=J)8jkiߥ t`o!3g/ڦ  9tKCk t-8'U^=UhAAٍYВ9mT  ),@fj&e'%...AaF ;E vš,^>vq17ĮM@TVʕ%W|XrϜ8Aw>jRjfX5@h@7[AEB }z>P+?BT{222?!u3f;p!)SXz5V޺ӧwӿ?uu\ S@8j5TZ7WSwyQ+V p81 ݬ=l"15A@"xQMEǃG|2) WR8|4:=#Xz5@Iq1E,ml0tr.I v㿕ZgQD>ƋTE- Fq)*OѶ$3KجinkCrUaژ(hh^02>mn]V|MLL Nө|HEϧ9J9qQ7bD`zAg~Yŷ'OK^\^={_7@ǼogRVV?>yYf&<ȱ#Fk^hJ@X5zLA/˪3IH?p8۷K.ǘ1cWL}mo11n۶YfѾ}{wNz6ߟn=zi!G)y#QB`Nl6U\jO ;i:fåK7oIII 0ݻw@zz:VMBBB @ F v;Fjf'#ak$ŠξTf"0WڄiWc$#"jeW+U!?zԵX,tX- Szһ""\79g陙|r}vӇ-K/a7"C kmcm>I)IA@ٵ3BK@J||_IIi41+&$`<:>gLAM\ )W߯οUZPS=4V7=d G:yI'33_l,pgRz U4MX¸>ݮU-3h (M0dȐ!l۶{=z4 |1b;ǯq\ TZF! &\n7AIҝs3'V%x&:62[29(P*%&UC[؛#_|~v9ϧK|mZv j! Ì3!==D<uuu̟?#\.YYYL6Su֑$ITUU(_9Ы+ZuL꥜뙚mb-:[ڍ4T&A\7 7^<73P0(Pی~I"v 4oPLVHMO]T}ddd_ 6;;$1%` ~?:'_yrKN룆U5V߀`d$ELԵ}6NҲAB׫lZ} z#ߨ~huǖT%j5 5 9<0P~m8z`Pw7.X:☑LUUX%K1s&E8iEgEKރR1-KB'%xnS'2i$t颬OLLdl߾,{=n\.r III,_ns1e6oܹs=z4O꥗7ĭ=zPnvӻGÇ -YҤ@6%8ϝ#vb{DHO'offAnM-- $^/*PxeԵl2nF)//K.$$$P^^FܡCF$IY˗MFFv| O<444OΝy뭷pH률@ DtRЛoډQu.IG(?D9Y14,?Z j7?@ꭙ'Z:2GC#L4GOnag)YVI0P~=@4s@V2Q6611kײ-\SN$&&* /ϸq1GCn7ijfMrN܍9yOvp).b11ܺp!~eENF֭Le% 㣏"jZu|zj0GcFhÓDv;MJŋ3gM3ǎˁ8x dʔ)K׏B4nʚo (نlٲm2qĈFrHzÆ v&OΝ; t֭@~/_vrqA|B(m)<ӦpFh''zA(-5u"q hCPu]=44yf$$; O1gO.: KIn;mqYpu?s>Gѣ̻zSSs!Ccz@%ӨEF4}Z>|iӦPXX9z(wfĈpQtB6mصkrYncǎ%##e˖QZZ̙3Yp!_|k׮e̙@uu5tO_;*4>UAz'@ VddJ _pq~(7z+q)|&u q)7.66iPDA8'II>u U Z rtýZ0Y@ZZ>RuƱcضmFv\.JJJXx1֭駟m۶TUUpBF),,G(}9\EN'۷緿-}E) p8FEbbb@oRSEpqo PȀS&`ӀoeP Pj猶zi{ַ&ZQ%' Br@Єkjk&͏nma ].shxn߼/oޯEػh9i{eJ.^sgDCKވ[ @t'w\...;~z6lǏ'''v!Iv{S^yw~FϞ=ٺu+K.%--;RXXȪU6lPH*^N:qzA9p'NP w"p86cZ0h7zxT}-5~#v> ml˗`W maTyhiη^^h)|y={xw'vn*'m"~iV~tKbrsyO7n}F%Roj$v%oѡ=A/W@'Vd=zp%~_@LL Ohm/^lJ5na'?IJ({.Gezzh?Nuu5cƌQZƏ yyy8q{" :Z x 'К9z-`ӘZRЛLaUmWZB"zuߌz-!V5CBʎЂrfiiۖL0bᆹsYWRƒ-t1Ӧ/HݦM =}-Mq`FAXȑ_n.[dl߾O?%cG&lV= #I X[Z֬YÄ 8~8%%%v;;;"/^$IՋ>LuF۶m)**cƎ}DZcXngbPVVƙ3gh׮Q:Ͷmܹ3n/\eNe|jrVa4#xu|MFe܌kQ_ vr&(/@[*LT7^h`ał?bTLȦS#Ǜ͘{>9^/mϜSS]ͫ+Wr)ʫr5p8xY5y2yvQ)u8|$;v 7%]$F8VPE'N0y"rЌ:tF<t֍L;^t)?m۶[s=$''SO=|@rr2555s)իiΦ~QUʕihY4 J^Ml@l kl-د6*gv 53` a-<,:uB.k|\XcwMO1cusG6lq h "IIIJt  vjN5ʢgϞL|<}m۶nwNQQ$''+ǯfÆ ⋴m?t)bbP^^9993.^`K,@!J^Q Iyb&`,Gm (3Զj |>vR.nb  ?QrQi񐑓C߂x駱Z?;7 p1n^/LΝq$'l6.\g8GR}o2|Ng[Uij`!}; }y>A3e[7HQlWI|`PGbbbF6oL.]p8;wAx7p:dee/KfϞMEEeee}ݻ7x<+Ǘ+jGLCP(>)DJ`vMRPPc |9.ѹzR'`d 3mgmS-hGZoE(D.FկAI"g~~rEbb" .*"ԫ)V+Km[;Lر#\xԌ ^}Gf8qn:pƍ 5 /Νi,)ng\n.c s)Fq\>Jӧ9~ʌ$Qb1(#M$?Ecڵ$&&~Xf҄‡~Ȁ(++Q[[Kbbah2jfh)%GTapQ`8mj@}#zL@5#NLL UUUt:dl6n CC F!MsZ,\4y?v>[(.*bL2N:!Y҅fqNŒwWWG\>73\X^ae%.7z^/1۩ h@VH*Z/w~F;A BSRRd̙lݺU IIIi. G @c0"%FL޿?JK?&PvSz"KA_#;s&n Y||\6egχ;v钖>}>`xL (  PRœsa8?9=6϶n%;;WdN\\nl?cc|oAc`WWp:m|N87QԚ5؉Mhx)G d[믝-;vQSSCٽ{7vC宻/ ?.QA^y :u$ǓU.Ez-A!WMOPzRjr2豂z^ .PTTĹsxGq:,Yu֑իݻ7)))L6_~4|.׋/"Nzri'5µj@}~!sm&gk&q <]vҥKٳ'|d/_NVVcѣL<7vmx㏓ɹsիnR P+ORZlh%«Y($..26nȎ;t{f޽5'?Bˀ9ڵtb#@@rq\4ˍŅgƪ]ߧYϝ@JsuT*?>>60kXu8G8skǎagө_Fw9shi;vPp2r~1Tzwt[DK%T۫"h֠EƔ˖T-ɵE_Գ>X$Ii?̨Ql̛7ҥ vom۶J]TΜ9sXf ǎ#///bBQ@LEK0 "C jyWILL$99ŋ͊+x(..&>>[oD^~ez)\..][n444,n[ؘ&߀CߏG+glU~Y\Ԯ|> oKGMEoou3g">ܬf͛2΁9<},}5$_~{Fо?Rv4:w[PgOZ̓P}=E_ZSI7R˱ltڕ8Lɓ'zsePN+))aذaA?Nyg'--IHJJ <YYYTVVdvwAee%k׮%++YOB#gVLmQQ1,֔>% W_A:5ˑ#G7o~'x=ڴioYhL>?]qFŮ2d:t ++bccUW5%^v7@ 3Xբ}C}=aPb"e^/:u PtiĜo`ru_ OܹmYʦy&WUv]@)>sFwY](hCݣҌ3x饗Xb 6+VpABmڴ$_OQQ'N$))T& i_V.9M RܜD{ TF}v[G /R >CΜ9ܹsIKK`={lL̙3{֭Nb\pÇsm~fϞM\\+Vk׮dddr"^2nn7u~?H矓uɉlp2۶yD.7'8u4VT⋌ɡp:i\$ tAŨlJYz~c?&++e˖ѽ{wƍGzz:,^Ō3(..&11Qi16`ڷoLB3zUfjӢu#a& tM_@a$^5/B3m4$Ib֭ 4P(t@bb"_~~l6 x衇w˶mED @}}=o߾JZm<<~?@@cu]WXJF6ȃHc0Hs2jidCyy'9!]vuHQGnJVV2j(Çᠢ={e0`or[A(+|ڊrmB-#Z4Dȯ,`໺>I->tN'999<~nf233_B||IjqYڡ577Z' \IYjRzfh6 O{ַ޽{n֯_OHMMtM0ŋ8>3|>Ǐ׵Z3@V|-vƖY@_kh ~`((IM3 @(U)ݺucʕ ::9y$o6۷QF!IСC7N^^7իWsN,YkV ͔_׋nzqT, F 2 µ< } $B Al՚^ lTWWx={6@9sP__O.](,,SNQTTѣYp!.]g%-- ۍbaMc}%Ji@BkX!\ $feU=;w}v<9999?IxGy뭷HHHgK5 baذaՊ[n@tbheˋU^>ߏ+FX џѫZkV~Vh_}2% O2}ͤ3J ZOPPPCHKKC1}t?2bV+ɤѣڵ+… ۷\AXN]Z(Wوl'e"[€#FPJF2d}ff&&L@zArr2K.e8N6lؠر#?я 4,h#|KS؁ BN0N@Ӧ~ O^f@F)&$$ӧl<8N8o[rss(Ջݻ+t!FIϞ=ROGRdekz?h=@ 0]%99={0n8$[|)ϟ^zB~(ᣧz#G2}tA^*vʐ!Cihhr).z>5xï0 HML&]Kg"'``Z(0|}N'HJJ mڴBnؿ?|' Xddd(e'OdʕiӆCrI^/Bf,"h~otz#tZc ͞3*a0p8̟?_I?U\V zq\|駤Ç0|DQߧgϞvZΜ9ٳdee PM ~)e6qDoNNX|Rd֬YJCϟ222hll~*\7\E~-j.R'J @X:vnөA r9s(vСCYd z~bbbӧJ).uQNT&M~t .jU;-4laa ^C50ԣMjٹs'L6Ǐ0o<)++;G/bXXr%{tޝJ8֭[5jR`$))B233ٸq#]wYYY?~> (]k … p bccܹ3 +GOL@Yt`aم@T_~Z^~}doJF^# YFE[@v9y$ݺuSun&rrr4hV_gRށ: /={uQPPƍIKKkJ6 Z+Mc6퍔_XA*6$P wSNqגDvv6/>O MUjwNaabÆ -[tR姟~ʹsׯ(((`۶m :Drky3g;HII_|4 _TT%''P(Z&(+\brS>3 U=t{u@p8>Bbb555̞=0`ƌC||<'OTWPӉȞ={ؼy3C7g3Z+E-Y\zӣ`',\AWj 򯖄Μ9Ct2ZXVO?M.]8}4`߾}dffn:jjj;`\po:֯_Oyy9iiiу;vгgOn7 4u ?qqq 0$$$бcfQ`0IOOK.:tݻ+5EQ"++_$$$??\遧WNfsxknDESzm6 5o}[TWWNlll> NbN>ѣ9{,m۶U vd EM6G׮] ͔j2tPelP: Y=Yf( #ZU7BQ+eҤI,]}1c駟ұcG6mO8p }roS]]4R̙3<Ӥ/Oo~| :$ѯ_?FAϞ=yݻ7_~$''D .HLL;`ӦM>|>}r"́`0a7ٳL>] z뭜8q.^nRSSi?OHLLr)LF0mb>̑#GHMMe̝;Çm6ƌ[mAU[SZ0-)^@M GDU$' 8pgW;HRRwq.\ ###amm-3/553f0rHɓYt)6Çs50e^z%e0 8pr |u]믿Nǎ6lRr[2%hӦMJKK#55<p݊WWW+P^6/*8s 999o^a.++Gtڕ={PQQ kQ駟&33S7aF~oٔ ӧm*f ;v[cǎ+Vpw2`{=o tR裏0~xz!Ϙ1cԚ*ڸjŗ% ߚ(КEʴET0'dg%77۷駟… \ bbb?>w}RB\v<=?Tnݪb ZGYY999[Q|=|lٲ'NꫯҫW/\xUV)6ѣ#ϟ'bbb8wÇWʣQZw )Sx衇unjӦ \nz!==ҥKӟ4@bbb8s ۷ YV,Yݻ={{rȑ#6mڴhs I 0FZhIh%a=L 2N@KbYp!7oy摖ڵkiӦ ͣ˗sSQQU$I;8p +W{n~(#ի>sw>vʢE8q/"ؽ{7XVRSSg֬Yk.Ο?τ 8z( tؑYfqYn7=z(%I`jڶm[vիI֬YÀp:jrYuȓ6^2[xgʨp8dggG1o<Ν;ǡCѣӧO`0Hii)lذ/裏2n8***ӧ6m"99YRqNZ -QF|=W6zy(Mݫ jDOxRQQ^bk׮l߾znŋILLdl۶G}Ν;sbccwW^<Ì;'''+(TVV 4MGc7xQ /KJJJ۔G}Dee%}TUU1sLV \x4rssٰa[lsά]zn&oΊ+[:~jΦSN߿>^x6mDII 999;wI>}8***ظq#C a|s=$$$ IHٳ'O<%%% <;34^{5C]]RX]C;/Z{dPLhM#[$`k,WOORaL8SNCmm-$QFl2ϩ5kǬYH۷dffR__O `餦;(txvZRSS)((`ݺu 0@ү_?zɾ}۷/6mfqsw /}vzŠA"FF}ݦSNeټˊm~7"W"|>%]Nѣ3gdٲef„ ,Xz C]] lڴSBqq1vb̘1̝;6m0uT9B۶mihhkso[̘1)S0dΞ=Kbb"ڵkiTpDoƞ^zȢ|dZӔ43PV2֫bd5^z%;w.`K.)u?w]6n?ҎJ( O>$9qm۶e…׳l2$Ib̙tЁcǎ_g}D:#<ׯeee;w/>}ХKVXG}ʕ+y'aػw/+VM6*4q 4H4L}}=M61tP.\u]? B8N 7Nw#N}gyrٳ'֭crY:v0s%9r$iiiv[ң7uUW)sh:[ F(ћ ϖd gŊ1k,bccݻ7'N$66VI8p `+Vl:t?K߾}Y~=gȑsnV+ӧOg|W_x^}UȯkB?92g:p >|$&&Ƌ/OeŊ$&&2}t~m&O|8G;v뮻EΝٳg;vdwS"%%%,^  /555JnNΝѹs+%\ 5;ږFL42iͤhNG-;I”ҵkW9z(ǏW(0458yl2>L޽ѣXp97 ڵe˖prssE[*@sa3grai-[p(S|ׯxx<HQQ\.N:7q1ٹs'c̘1ʃ-Q$q+TWWӱcGJ^/h"Oi) FI?FEKz-+͂49]+555ddd(o^cٓ[orE>sBO= w^~ӟ*pE,Ycܹdff9r$K,Ql@ 14>t~ߑǝwީ0YƏϊ+eӦMJtd,Y~qi̙(?\,#m_QV鵣J^{oӏ 0rpݴ@% @ ܹ3;vѣr͛gx;uի2d7oP(Ę1cđ#G8rOk?9'NHDII )))J}hǢEعs'IIIL2%¿yطo<}=Nll,7tL23}te\⾨c45Z^e@_UR.WȳLiY;w.6l  2}J9i$y|I&N?3h eڭ({ʬ$^z%{fѭFyUvZ#))) ٸq# H&2EgFk| F3ZS5CZʗ&L222[}BB_믿N~~>o;~xj*6l6w.(([ v]tfii}4%V7 $_[LmmI3 o >/"1h $I8q #jM^}K)* 麬F@\Zze(zEQ2'O#FrJΟ?OYYyyyuƞ={裏E˥[0l;3u h Ii'&lT$~Vp#Nvc5i׮7p_|nFv;7|3{b0sL} "F{:R dmHm"πR$?Fl >I&#^0hn1 S2T9 m-jWڲsdP,?r4S"hnXiHqJ.zf_ u&bU2Bk@=˯FT_EuZP1S"0&1= z}N@:> L1*$ZAQL )vmr*4ŔAd`TS%Pȯ^ziÄW43|L1M;^!ϖ}fibh r\lĈҷz2-KP|&0Ŕ/3h7*#n2SLJh~4:qKe-uM2)\%Q~=PhL0Ŕ54Sڋo @qM0Ŕ#Ǿ5&3Sh= ZSLej5~e6fApSLz[R SE [ߚE/ ZbJʯUhmW\uSL>j/ҷFa[ L0ŔVZ]SL'PVU `)_uPo"M`) )JŘh\9M0Ŕ/F ZzF `)W )}kBkCk L1kV~^zvb(~k O(^lnk)|]ŵmZPiɜ0Sѫ@F3>ףј rGP(Ԣ+e EeSL ,F ԩx%NL1 hύl~=6bF @/`2SLGP(dW -c @  eM1KF#=z{J0TB!l6@@9g0lovKһxIF$^>8dN=RG"ߵb⚠}'DAw`(o}7Otuȝg;|MlGH ?rxѓD 1IH}4F֧$e}>$"F<"&MGr|IٯTA>JqDLSQG _z_T ozyf[(E"DIu~`@1A6},&b`)&b)tح H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FaIDATxٯdUkߚn]v:1'`c1,! OR3^$"B % $ A ݞ=ηl9{:UN$Vo nMS   7*~L G?@_}G>SLGgeIgJ=>Oh&yi?f{QЗdE>-}ǏXO>rq=e( "lR^zmEE޺o1$e8XWۺߏ4 QB^yž_z]7 c>\__/KY䋟}Y%Z-bh~ T$IUϛڒ34Ϥ ZmƪVT|`>4]\EPs YXV` )Z[kߕ%uNTٲOn=2:+6knڅ~9x6$9sƋ\tuwG.x4lVi{:ގx&s~F&i8hs4x-s=53W })cfee`vII$퀖߶oѦg.XYl%hlfz4:=_}z*}Su]miu}ݾ=ս7ۗ,DD3+:  hV͢mt!1n [ vfGo+Ki@_ĥ R/T?E2a*mVRcr775d2bY,Ih7b+T \"MԦѡykoy}/k2i@? {yweHt3zykksxSo{U7l"!N$GKC pwQ9%†M Z"KΜ=$^C`k t'OB  F@!/FQ1iV 2%P"Pn`:KWw58ŕfV<h AS6?|>x4Յސ$sqڴzkx>0@.vGcWPE.o( #s Q"3r!>p%ngZ= V@s+,ٽC#NC+x`$,IMIҡteg_^;ΔOUUNWw9Sh;d){ugG~.]96fs y'M7Gg_5oѥ3g5rN"pi>߱wt$"P[;`)$U`}?>; DIFv$ P"=.k$&m1{ckOFۛk6'q\}[Bɹdgc_\pHKe1ǀMƭw8]&%RZq c hEH*fn 3eFʋ@.^Lq^pIbp2w/O޿Ҁ_y- CF(p<3{߹Ν=;B;:˒Ue}!@8V_^tVy05DV_rŗ4*4LP婋Wt2ʮcҫwQ< \$ΤϝlKW̩2>8lz2ҳ_*f^Li8s@*0,WrS*V&%[t@dwU=Xtp!k/9X+Q~m䴤۷ Z#?Y!ЖStq^v5W$0Z&|u_ãhO27!?ge}zMgyF\^[nз[ cJյ?>1?x#~`׹4q}GƣQ%[믿 Rn}YkTna]srY;^6 Y.0~o׻M++  p  Q=WW/oX{7Nro+<=>mVb^z-rin*Xз>gA9g_ pή_ pp&4Y<  pk—p@ǀ^-(ln|5YBB]wZ}us! 7}vYp<@I<B@@l^ O=% >+pB;C|t1R?Dy_˯ܯ&}=9_f-}et}`2h4Q?gI%Yq崷_޿_o t|.=_yUUU-,,gy?#W[RSuIߦ}[g3p*T|{:rzX׳ VC3KZa,\bֵhS,^Q?mӒ\[~Â(uͥ,5,yƸx\pXiDr.y̵sof)G!DI(&GÍ(f]jKa06&+EuҾ[W;7f|(LAF=<6A2ۇI@4\IN*$@@@@@@@@VOPpIENDB`mldemos-0.4.3/MLDemos/icons/clearmodel.png000066400000000000000000000312031172143270300204050ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F'IDATxytTEt;A @& AP hԣ#QD0 (#(qMD(8U ˭}n,@B9۵ݺUOV{* @B( !@B( !@B( !@Bj*Ͽ`(K̜E,k>grɦmg nW_ť| )-njv>H K49`??;GXd1_6V,GBdI|2 B~ASa`E—["Y 2rٟMEyG匄|i@ϑlog>{;:Ѕ f)j] c ")1t<0 zB1 QtKG7 g \ii \{9\Π{SߘWNW[XTE(\q ƃ˂?zNf 2Uv TXeU6hm4u  GNjJ7j#zsㅶOڌ&^F]lY ՅTT6j;i ։!l:?L#6qTkD1J t%4:3Ljr-"\Ѫ J_PrDt@Aq!m YgBN4Ev @*vq2+%RW jT]1v)4N l 0!t>}i4#YĤA,ՠOP?j ު7LjM @/@0 7oNj1_שsR*X,!,E"eDEAU으@Qqq5n^AnK|ӅRjKˊQVV ӃM▘6q[ @qIi`4/' ^<#~P &.)I>GEy# p[H:l`H;^Z@՝Sh' Gn,a<6^0L,&kP-@l4_!/,*+B 9M!7̐NIq 7Q>s (oߡ~=o"tGRo+eeG?]G0XAǝe7N@*[ЯV#\^p*F) =V$̾%}g?!}=RDB$ڨ+a3K[חSR#MD'` /Vir qEa@ώDYikE(..3irG>Sd"Mi{qgг `C(+Sy\ڵ o yo; cC,S05B3y J|с?wD _`;8 w홦88u>ᅱeY'2EvZF%-m-ˀzaZN@G\aә은(g XV砰ٯ/ba - y(+>ٸCD-?TVv=E@\~wL :gn/wtGDF B+DU%ʼmc'_X$4hG(hy-5hb|e@;l%hANˀQ&M;/%I@ AQ45Y+Fϼsܝ/@S2 xPl| `Cw.ֻ3!Qu@uri?;e}>e@>0%y%ò$  gaYԊnBQI0 n>er,] rF ADDA""0]nܢd!e0 Qo"ph)4kաb$(wӸodUיuˀfǟ~ r#閱 Iq@څiѸ h ժe NqtҴ `'PC,^VLN@O*zaP,m!7)zEװ(&`+Ygб]LD:"tF|%첐: ,KEP[?&F(]c%|t( gnԪq4>e `}-j vێen "8 вXe=а_S}YRMJ,zk0z+`8px}v[n:}JKTxJJJq(87il< A4EIi) ~=Xtv{[b>gve1L^io&mmRЇWGY9s_㊘gw.lV][id{&dqYo6 6˞xn?͞KzeHÞasK0߶ԴZ1&+[+,DnxЬqCz+(BYTD>T%5!!OEQqoi[naMR yi!8IhͬMBjӧOǙg 7\ͳ:/t;_iUǼh]2Plgzc՜Q=5TN.3&ƂJ,"_p!:Vه՝fFu~~O4E"`}THT`B0B( !@B(K =ho@ Vd@8i ޶a~\XYk)a<]v  QFJyC]g]N W>c=)3M%}!FFF"&^ @8*ss#밨ƝpE%̬CN-TrgaE\t]7reBQk'*ж*q'*֨m .f">BB P!BB P!BB P!BB P!BB P!BB P!BB P!B`֭8y$+P֭CӦMѷo_?ׯgZUP1?3fܹsgϞŀX9ŦiiicDII [\ ك+VѣG[^mڴA= }Q84SXX{|oߎ#G7 N¨Qt:+cB#O>HHH@dd$/ PYTUň#p}-܂riӆPʲe_Μ94ZC(u2H'99;wF_Š!tCBB 8w|AeB(8M4ԩSYSB-REvލ? PRJ߿ @ff&4ie˖!55D8BW^Aff& 337o?P+'''@*~\.Ξ=[aڵ޽;%K ++@!%%;vԶ6 5?bHKKȑ#f^XH8Xp!ڶm!CԪ_{1۰aFɋK D̜9<|0}b̘1=o/,֭nEgϞRcNjȨ瑟|O?4̙n2BW']t3н{wСC_믿ĉ9uF. SLg}Vw~ _/&O "##K.Ez.9h߾=jL27ndo|X`}]ŋyf8pNVStt_B Ν;_ŴiӰo>[o"99=@hw޽Rb?`ҤI={E3E^z!..O<%{ ϝ;gvťHZᑔd7p*oÇhРylڴ ͚5;/.++}Yͱ~zˊ~1Ǎ7ވ-[hRRR[ -?&MBtt4/iӦNgϞ=W\ǰa0`^Oj0aL0-[ٳ1qD4jwuLrV=h\bt SNŸqЦMJӰaCw]gbغu+"""aƘ1c|MJJW\Yf8ׯR!Co<~;j+_|ԣ n:Zqqq.۷ڵkoE۠(է^{-p:ܹ37 @M ""1110ayz | v܉$?P / ۍ.] *,Y=z4YPիWX~g<HOOGtt4.]-[!$("sQڵZz7áCaV24rsse˖;v,fϞ]4{իnj @U),,G}k׮ř3gm۶^%0d~hР`HII$T?xպbpKz1-b!++ sѾ?~K,Annn5߹֡C 8jSQr0j(߿j*ovz-dggaX♐sU 7oE̙3k_~?JѣGpFii)6n܈5k֠gϞ;-ۣ -ZMdd$ƍ;jǞ}YW)ݸ8u. IVVV^Ǐchذa}J(0}tM>~-݋'>dDϓO>e˖9QpIܹ0vذ`3~!l2,X}ţH{i^^ۇ+WR3tΜ9UJrac=Ji^uUx0p*ݛxP\\l8F"N#s=X}иqc@f׿<ݘSrQU7oƢEТE =wݺuXh`޽ػw/:uÇW 6lXkb8}4m۲TzFWFtDEEaز+\yAvZİaðm6l޼:t(ސq"##qw_~e% @mux !!7tSq BDDDhhIʂo#oAΝquaسg+ЫW/t ׿O?Rh\|1m4A8v.\xAˡ*;|HLLC=Tc쥦ᒓiӦL>oH믖_uRb2dN: bذaCo=tJJJmo;v,vZG̯ꫯjSRa:vh[X?>N:{ߖ7==C6m0yd,Y)--O?ya͚54h-[V:t֭[y|Cr0w\@A'ƙ=<̎z꡴xW_}gyʰi&|ǚ_TT}p`ܹڲirr2&OL Wߝf!+;^fUJo_C׮]1g?p8gϞp\܃;3hRܵ gfffb]U*mv,۴*e4x01k2NףeB^T4:JVYYYؽ{7OCKꞄU>ҥm۶0``в#P~}rRJ$'Gt1açO?홿Un[%VK 9a˖/MNůʽ4ir&Nhv9̙3 ]v/zU"K3ѿ2p7뜑lKLȅshٲvq۵eeehܸ16nܨM[n%D-NMz0w\ :^&L6׵^N:.9Zj^zaԩU~P?koѢE Á7|˗/ǚ5k0tP5ꢜ1}t=zwE̙3Xx1nc^NwmW_xaرSr ԩe=RH]v^? `ԨQ;v,7p @ C9@.59iӦ, mɓ> 7#BÆ 0|b֬q8Ixq1YEEEx'p 7$$$`xGx.ZYO>{ȑ#Ѯ];4hЀ@*K.]pB{رcw{sс-Z %%J53c ,XB^< ƏϋH U^z݊QI@-|r\ZLLKKӞo(DFF{= sEFFѣX~=vY-lR{t !'"":ѣGk7\.L27q @j ÇGZZ~wbȐ!;gdS̟?~)~~ꪫXbǞ={xb!0vX$&&"22晜իWcѢEq=T%(uZh4]deeaȑعs'<{=\ =z8Fhۮf͞ͶFXg'N`ݺuZ@||s( t~L ;-RHNNƠAЬY3g;C &@] .>#|hٲ%z|^ZLy>|86mڄ뮻z2R+%:-r3gČ3{_|׬ȥNAAwOZZ9ʡKcyFRRE{e ɓ /&Mb.a ɸk0n8$%%`:EѼysVZvBhB&!!u @-BB P!BR(wP AOHݝP}e9 SBH]4jKRsT@ SBB P!5pv|,8!!BHRB LEdHl! i i3E2E~#- #'Ohɐ/wrd9s<dO-a$OV?Pa lÔ2:0[ SA3A#sO O>:I5*Z1MjǍqHӛ:yS+?_]Q=S)Ur⨾ղ &uKP!U;i UFw᤿֌ HH5 z̄QkVBĄ> al|IPa>!t @D(J09_<}zZU$@B( !@B( !@B( !@B( !@B( !@B( !@B( !@B( !$aMbIENDB`mldemos-0.4.3/MLDemos/icons/clock.png000066400000000000000000000064541172143270300174030ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FWIDATxgAT R.%J!P.%PnJC%)ѷ*}>VijFH\%y9ޙݹ=53g9ss&ɲ,lo]Ԑ${@X|Je2BW@P8 <rEOt೙hLoI?=-mcei[v,nÌ?ޛ][,8=`t}p2WH^`W ;Wt%蝭 p";}[`V9Sc]˨nBL9ިg\XDU}s#?06AНugwh#6rI.ʊG5ߒ)l3Kee;xcHտw!K1h& p51L2]8D4ňf ԑ9axVz>"ُQ0W\O1GQOI #m9r]:Y]*٘6%n9R\3{NOjv"sdkeyc1ꗅ / B_"0fRSgyn6zew`IENDB`mldemos-0.4.3/MLDemos/icons/cluster.png000066400000000000000000000607761172143270300200000ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FW)IDATxuUEǿsέt-ݝJI ؅&a*ݵy.^`1A(w=g*tUMP6&4H늍q@?I*T,U4$d 21 I9ED^ek~s=ʫ3@f Ybax/~Y֙W!ȼ2+̺Lz6|fG 6)BdW/1ۘ|zOYGzynf@(S]ߺ]_eBd]<~IIs`3r}GаYiYW*2/$$'Z6!X-&n`!׵gr#4HIMQ#&,VKz{ 2FPh>kIIsetL#`:a2rC'f^H/ŌWYV#0 @W3dJH)s|<%62hF"}="rn 2+}I#D[1> | H#v<+3 -0 d52s]Ԫ\ rMf}C|e&&sW Lpr9lvk6`;_3+\Or C^?S4g(kdvڬ%svخ!2@x',GfiT^o戞e\ i|Gh/d6^f>@v/_z/O>w?ڊnnv6B^ˈ~l#j ;* oD\c@x вI4FZpC LBHIu])Ym^ ՙFʼnK@p"/\&0 uXI3g0@| AJM'Fn3m_k Bxy3N_w{d.by z۫\m#y6O[.ޱb~~c^cQ圓xZ@]KrxBXrH`0 MHq\C8.QiSS ȑjp}$őqZ윻t yued{CpY2@\|;ᤏ-Glb zm @)@ d6Syy6Ck>A߷nۑ{3{m0A@_fȍ F} xނZ4My<-Tbc,%́ah$$`y5 őJ-5܄$*.@BO>.;z @R58ҍ;֦!?/DHPzt-tGdM\퐆e>su]<>{Pz{2Gl{ +`3?o/ǐ!Z )FYSy)\ۜD؁%oc̰H#eQWgD9Dd`{():I>b_F\K<_2R=$%ahӰv[@wta->pHJN )%Z#_-=`>m"G HMslc׬6m`סSxEJ#ф _u^# lb輔e]Y-dh>C@4 }# 2 xr~@r4dҰdEM5۬,^4S&&go5ApFXp NFZ9yBt1_B` [bP6mVHBtl^of 80 lMq +V)k.[:y猬16O5G ,G{7hl]Fس >e}L(SЮ۽7cΆMr9挬 (}Dˀ9V^[ |cZ6}oW,f@߀ݪ-1R2d,O f5S0oƻSaEgnH{*.ɦG qr_!61y0MenFlVsʜ#vƆ%mYvdxyBbx!}e ̱>e ) W2r, f M ̹{07|df7\Kl1n>ˀ7g0b*@J]7pô46 v`M /cZ\w#y-cF0>sɶ c'`[mkNq2*?0{u¯d  voa9my{/߸-0hG%kg/\l2c}b. 1%B ͱHCb|ݍD6L'iI,eԆh.3n9bFw߶ccnl@έuv IeA@5 ]W_R;7%h' k[sm=px' `2yKy*:>n l6Yqܜ@.;s>c&`p\n7 4 ~;o.`1geKcdsy7V{ gJW͵sn0]~Z?07 3uYϜa?nM(G/Gꂟ D==, iȑ_eH=#Q"c;dMhJټufk6v .ɩ<#} p3`*HC',Bq!q8K7!޴hBBqT\rʕ+Uk*#G$.>raRRI7FX~N>?3~|gq~#Mg^Œ.kHLJ…ȭ-\[C]ǰy7cu5['nf}_\7Û<ݶs:\{}k墎Sh7%f<-7=Fm'-r}9l6 @yBΑˍ@`Cwr+*,zzpg͔+p\ogr6O,7yMٸnS%0{## Hjxc7_*+N'=(H5Bq[Ls.qU* 7aj@QP(P(J B@P(P(J B@P(P(J B@P(P(  (&]_OmhԶ-wjnG<ɗ?s?`tStUC*n9xWt!塇Xָ1!WΟ[ݚˆ&`uws>.N5PaxZ5-YJ={ & NlބL "\_ WG?w"Dъ)Sh԰)Joi?'nh?[chh,ݲnIhJӇQl 7i+:m ) &?o'5m4Zjn(6'~'L~ƍ3:;OLe\]|A6iDAM'D6 L:|]Ç3O=q&L qi: #Fi` 00fj׬aZ"TYݻY4MNf[p0n>IF3T`Z&5kT<F@"\I x fZҶ0;og谿,XIssQc'k Yu;|OxK4ח.=uhYHǙaƧիCUUqo?,._F9lz/GaΞGs 鴛%/%rF+=D4 y?8ql0f4M!4*KI[^)>w)t?"@ilHu~Ip8 $MIl 0X3|!NDHq1N;ǠokVL1iJRݪ%c.9xe˕#ݎ9$@Meq̷bՃ(̔.B D=jO%L s.U&'O`,\~dޭ"Ka9y>.7_KI!x_JfԿR2&6A?,V`M:cnL @Xf[4B]?A?O52l/\޴=i Фdy_c˶ȁ}{tKut>q+.p Q󫉸g@>C?qg"epX &rff}15 7JJF;tsB#E$B0[Jh2 ޲۹[*V ۶ߠ/vdE|&4-4hPKV !)`a u.=>zkPhQF-]9o6 -H4 X?ta0jhN+ǎP08NX5.୻i@4Kҁ&0sDzH#HӘ-^c>ϩ ^yiz{: 3 I["= Npv (7{;w|P$/}u+i>u%t ˓f_|A/W, Ÿ,kv7:zHt6X:D4v$se*e֬#O` v]a-Q7قߐ&V)(஝t҅)] }Fisj$r^%56K\5$8$QA> vpq >З{;WV cx;y;...XFJ|o4<)8zc18Mj1hz;5.1{VM_gc(kʏq'n9kVfT<:qӤn]{9h?Kt Kg09La26""5]٣GGJ:>mǎ=r$BrPX<kT#sW~cƧ%ICt<}s2D=O,'>ZIy/\Yb1!0MRƮQFB5UP*ۇGA~ !qFdױ,#H'D5O"/@=fNffҩ~(k 8!`0D\Q$1#g=$P_=uHA`/REAnCIB%neα316L^rsHJ#2y N%ߥL< `} &1ñBꁞ =5Kox7x0XCހkbFt4/* Eѓ'ir 4eʕ߷/yܼxmpXoKN]o\_|A^1I?.76y)P5eyqn^u@1]h$E’4IDHw2A4z<8Q8e)n.uNUGVp$$%ti٪ !Hu1RaJ$aW714: 驼"%] ԙD&E@NMHMe,h xbZyE8|0+Vzl,S r{8i+Y)[WsI*+wQ ͥ aH?ρx<͚֮`Gh4 !&Aaf"_ďWbЙ+Ҥ)AV@:8(M-S^5w #Iȏ jAD$J"а#Ab$RpO_˶={Fh(Q'N0YZ\f?O HB6Чw/Z7oCV(8ctn3~Y31ߋN݀WF4Ml6S@P&mdZ4Mf{!o޼|Wh@&@~`8 hؤ ovKI?C^Rמ<,ƎO'8c=|Qk1ęj3BP4BDBмp+WS?BxH'n;ӫ6׭v~m 4qjMЀO?ɴ,5UcRֶg1ޝ/&N$8{J.XO; u ̄Ҫ^B~% .OzS (W GLɤ)UH:Ǜ/3y4jEϏCm6~2]n}iv42sj% _wR"Dfw0f=y8S#`-^Qvmʇc>S*@JL ;^vqsN4vl v0 xܷ[r D 8Vtq 8O 2nغr+li!oez]ptM6^{e;9Phg* o3+AVDkoǽ͇~Y[6m䷼RJqԛ]bz ~E+p8/y1 4@,ir)DZ=A*kڶG5bbc8?v5b *mZr}=?)LG:H7z*PTʙ+Mޗ5Bic6Bbdlo⃈Oɻ i{ 9KS9{"RM)۝ƦKlZlfa8SY@ā#e8+hҤ \Xw*ԫ#U5K2f(֦U=`=%De+UjtOg4vÉu_jdx<:jvD$C>_)?9oO/2@R&X4 :a/,C5tQge\#G9}*T!Q+>ZUV='%> DT,ƷSq0h!u ^3OI kgX H[hLBylG<ĉbGh|>[/o=xW ` b)nƈȘiҐ%F%!QKT,Z_f`"d Nf . e$R\D |{haRRڶm,gˆ<`_;[1w5.YHZDLrB{;5 /DŽ pwyE?jtlHNc1V8,\yWMmAHd aHB*ըĴ3/ B֒BPjuX/3~~ƑsڶmB;ÏJ IA `!ap7KJ˖.WVv JstA8D:BҹCW*4ZA` M pdg 7Ƴ\bIҦJ;مbeeWRm+)14 ry׃zn%_ ,P I, O#Eppg0i,uN3Om䩽̝;ի%Lq` Ҫ=\6Y]#hNM`x! ekx7ч 7PR³IDž$TI98k+3=cySH +ߊ#t }Nz7G=o7_UX7ugO7l[ =yV&} 7d̝7kqh-$6!4"(&!IB-qp3 #$;ZEђDFCZ0>XY5xsԛ|c6Hمe$DGX =!K\ !$':q:f.%'h(X3,YE-aЯxny!%C^AQhi:΋_@8.p?àj`6x ~7 8x<8:ќT5koee@mK}:@&S2.WYN8a84 N9 Pގk rqX-):2TJv(ךdLC>BZh ycuvԤuֹGTyϱw'VKxTtb[-(x@ ueQ`3߶=p8Ot6EbEcof0ҷKx-Ѱ:c#?`7IM|FuD`>S?4evAA=I?0@Q t[1؇&Ť58u-II1̛7[WzoQ~5ʗ/DӦ8sn7cu"(h7_"`1Eć.[6;W?efߙvUHSh _O&ΚȡlhW 62ߞ|wo:$bq<g㣕Ы<ȑ#1<ɸm$ǐŴRc2cH}c㣏3x.ȑ#ٕݻՀ\ub޼LB2d<~xȏI6.tS.c̞}EtF=ѳO$22jޅ%y! !T` TY.Kgi֢UV:ظ9P\EKeQ}O{s(!h&b\Rq RJ<25-5ڴK_ +^~iYi m\'tcOeRtRf-py詿 Scco)gU9EF^iRʇ~{楔#t刈(GphyF؇[ %KZ `ڴY@ t <鸹}|0}w `Μ'y睡ĔG0BwH4pH\|9ټy=AAvTQo839lشy-iעq84%Cڗi|2N>͌g`68j?|.䳩ɗ(X x˲cꕫ}q?ʘPt=>Z:7fpI 9ǖb }=C[\uƌ=G}Iԭ~+mVT+K$ȗ/fs\矔O?}X&f#:zxOB¯hȋM4 Xp1l)P*+ṾZtc晡̘-?>ۆѣ_G$̘rh|Siy#ą8p o09|G7̯Xb Fƌ,hկGzXh~ɴ,[ 1tׯgX,uJÜ_o:Μ8CZm4^z7[֡Tɍ̞{;:L%<<^r#&*qX cuc1|L{DERf໌㵱ZTqRQUGPaK1s>i{5_q̘lg3f?ృ5h T"1@{7z7*҃N>1,3,$,/p{F<>y ā^X^C+xw<Ն]RJRPLl~ k"I A#GZǟ"JHyMb,\0P,p3|w\r(q yF0{N/>l%'NeQ!HaDӸq^N*ٳ1[G\ڏlli.l.OfÆUujZ`~ dM7x:oofy3pavE-_@hӞƋ[^nSveg~7a1} ICB< 3RJD`Ɍ=Psc!pm p*$}ZRӌN17qOCȪ|駴k!r^[oIK ;Ѹq#.eؼ?Px ^>*YcEez\ t) qLjhZ8ŒЁHyi" 3qry0դGzqQf^Deh׾-|?N|l]⩧^cӦA@S֯_ƓO#0W2&齊X>O^ם+tȃ4`0Moñp7b{VkuvB !9+f̠Ioϵyw_=<?T^EA,p?LrħNrn<$;d|Mq9/K"0vt4t/(JL^C !C5{.#!XºחIJ{ͥ@k$"X-i5jFJ7^u.4Gխ8~8N^gcZig眤f5V~cgsxrMeϞ72y1q+wR7n$&fkAr0+쳣1;v2.{}Ksԧ@\ѕѣbM 8X "@ SOk{zm^d &s ܎]4lI\L?xكt*=^z<̳|2( Ț=~4vq/.2~'?87A4tc;P (3[Nkr`ԨQoӿtBwpE/q5hx<.^x5&LCH)г*:wN77NϞy\prӹs ݻ+ڵ MfN+LDMH=T2F  hzE ztk_ T*.C{sy~#O%WY5hbbWb[@1qyŀ a"GJH-,J Uan6퇓kTXHH`*# &ǪU]Xj?c Lpc,$"̈́ x *TBr1jLYS8@;wWJ*Ur5G?b =r NDb 12;7dMxv*o C.($v41]OcN֮=TD1,LXs,Y2JGB73>4B/8n:э(].ow1in G1 )ocoVֳpfʕˍLjc\LPLɒHдv\Сپ}+GU'hWZxӧ(kXM;f*RZ0\yeH3V01+HJCxgDž5H 6o@s}fwg; > =]~Zo8qA3-BzvV Ef|{9e.SGH"-6 [_]4eX*DWH.-#{oп]D9ҎIHhđ/_> S.9nn ~S's6~R (h9>3gAl2`{#/8*QR.&Fi&ǹ{,Ng"JRX2Spcl$G ء#HmЎw>C1tPVt[L>5 Pf[ r oRJEt=)c>^ ӤIvm7ߤP~ O<6<|=Hc  $EƐ!)V8eZ%]Hx5M":ʚ&-ҹc {/)} ѲS?v<ҠN!1'IuY S֞erQuGwe Q:}+L+bBҊݖƟkR:JZZ>)OS?j6y̘џH< 4Qn]̑!hگs:9ڟd Xv>alv|w/fϒh' j lN)T ];g!;P6Wx8,>4{)`<^uNT>ju#p9ۇQ u{vmtDA))$%{R[]:<%8ߢ@+Z^4 ǎmH`t鞃D<Ӏg}.s=Ã@4C5z~@GdIJJ  em>9Bxpg/"ltn}p PU ͮ!s֌YlQR & D"))%kذbO_45wjZl?Ǟ={q8Z}x4(+4KW}#&2ez$O 0<AAR DΙ@g0}$X ,A`~q) } S"0Uv i="4] ӎӴ~ L )xG}hv9@]IJ3\INgҨN*+3(0Þ{رm 4b8t1ã]v~aȖ!\#C%{[,G ^=TO}r0L*.#o)@4hpvrRRZɓg8S~ѣ;ǹNK4T >t= :Wo8u0wJ%HዉSJ5KuÑ-B܋RwƯ^t MFw`_VXc4:`MVN'zS .<,[c `ۿ0e% *H$G~ԲiY IHR3*wg|wx y*Pbr$[@Z[=fiX,t/؝zO#mu3hٽý6}_~xhnPkII}H›i׶)K, D%P5=Ip;KQr)|=I}>iBhhAڴ^޽isOCTSgNIQ%+0m4Yǂ<rdQZcƅl`O6%0qy0aΆ ?,:ʑfGw_W@y$eРF*tm:|T~?~mJ(ҭj7Uyv߹eL2 VO\y;עD" \ R įsy}3TdƌԪ1guY9Kqv?LEI+Fy|hZÓ bgW1tZOwٶ'6 'p>l 6f V3=&(L3qxZz AD?93c~aa,Z< Hh#,h5:$D۩ 7I+[q b'Yxy`L{a-dX,ߑO>$2 T6~F~$58  <_^7`L!w)_E„n3xmWRY]:@ 4Am0V1{py ,b ş`nov#]ËMAG?H mʌ53tw1\@\TZ<\|s5Jp%KInјn}vn/g%|3mSBT @1`X@x$L|ڼkY'zK?8+G3;4 o;yg~"f/Ѭp\ף@k֏OLX&"-/DY4sgQL/q=5WhVQ=ק9xh?vş@itΛgh0|N!u&XdT_o><mA5 H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F:IDATxw|U?gnMOH"%t)S@uXEbR`DE!60"RJB o#sg-A 7_/f̙vy眙asqc"%  H    H    H    HUcg=tIוs%-bum.tp4m pzg^˔/⊟Z~l_?uru^~\v}LU~kpݼّ|{)Y,rgC!y/gǠ*4K j8 tLFa]!3yPݮ˥rUƹL,d0d@~2b @ YS$Թ!"!O%Rˡѣso!a |=yqY!AcϑiWă+|mBY}; ;pΨ,݁r+5D[ lkdPi m?]=ѷspIws@pgθ"ݍUpL$PL+B$wj_;y%V/c0eͽLdՅT9QQԞ*VnÔK1O ϔ-cLpOsg J&̔)k z ʅ `NB2 cN"@ xWՃ{'w.AP4F vD\ƭ1OGl *)L!UۗV㶛/d@SLgN<9'zWũ:K/30$|PJBaW l|qz=@J x*4<{/j1T"%̻GάH2X_!>F -`ZA=@vLFʄ]Ag\p h+rfIUs.iaԪh8%Kah۬ ~("/é\,-ABl }x *@Mj=$X7H=v$0zId{ fbZĚNKe * Mfi1 fh8 PQaNgPNȰ\fVLTnr q#9 ']CA1!Aj afrLk"JD1ˆՉ?yw"d C>yZebTzj+>C]F@T{aZ 4@v hFw" ^y J M\([5kg]AohPNҊ 4LN3BY!"6*Dp3L!x0/@1̧nԢ7 7@)DoO@Кv̽bsL@S0bx$IRxMtEc$Bk˪0h}m#-Hy]+mpĪ&`N*p#.&A=xa1lvgd @N^JDdж]{eTw$:ٳqRr`+,++CiYV\w{Z?^fď?O2_F&1&ܹ<偰+W\,X㿬r~ ie51+]gdς+]' VBd L70$A@ A$AA@JJJJplg n 3d@0u2ܴ~\PY'_W>e,rBǨ}=T!rciOy`Y<? "##ԋZG&+*A˜YX˾./s ?awxf!c5h[5d}5kԚ[8rAA@ A$AA@ A$AA@ A$AA@ A$AA@ A$D]㧟~°a0c L<(*/Y:t eO?4ѽ{w޽6 *-[}b߾}ta/=]Z###ݺuرcQXXia2 ^_TToҲz sNdgg#--..yD(9GDDZjh޼9mۦ(c0%-kܸ1~AZ{v(`c sL&rN3f/ѣG?e˖G}D'HHH#G`ٰ~z8y$=*+))ADWz+("::GƠAť00i$}:0f!...0A@(s)ЦMlݺ6Mr 9"!!p88s  sdtq B2W$EzfN ZHKKw܁ӧ#55ňByy9z=A"Bݻ#++ 9wݎ F8~8q)ux1bj [Fll,>R>|:uK\@^^Grsshٳg둚 8(**BDDL&SȜ[V޽{`0 33̙3ѿddd`ԩ8<&Np|gXb86m"""0a<}'yQСCxgt:1zh1BZgZxbرaaaXp!71w\>.\~Ykł3f`(,,dBǎ/ڷoիWjJ_{кuk$''Kcʕp8_%(<#xf|Gp8Һ{믿ƺuЭ[7O(//ǚ5kj*L6 ۶m}&MLcʕ>}:Ν; z|ؼy3?ҥK_N5k ;wȑ#7ȑ#ѠAcС7|񈌌ļy󐛛 48wzڷoŋK3 nzM6(ַl-[T,kҤ ↅfyuÁǏ,҈A8%%%xw۶mt0 >zhSK HX`Ar'O[o%=G p8(..;L7A@ A$Dl6K/q!.8RTT^{FlݺСCz5 믿{&f_n*~=1BQN wYAPYYO>@q}+sO;DDD 55Uܰ}Ԕ\e8v]l+'H!"N'Nf/6p2jA. (^Gv$aĽ~uW}y )jW?P̯TuJսܨz}2y/oȠ_0[XX!Cx ys&LK@-.2f9P{K_~Ruo߾};.^HQ= ߡNCiijJt:u7PZ<@^Wxjq wAՉ+I\KP7f_ƯnIB'Nڽ\+yD5ɓj/A˕օP1hy $D =V8h@(s 1\ (\\u+5{@@0kq4>jOZ$hϯ3?p3=SW1L!A?j8f;5_J @{nL4 !heo)ƍ?\+艶rTVV"333h#E_|k}}EM{KÁ7|| 2220l0zSNaɰX,X`6l(m7k,<ӈEqFԯ_ .DllwLhotC}ݮJGYVIIIe+w؇?uoqZ;lt4ҚΝWc6K_S~2 \e˖ѣ0a >9?n8K8<-Z.]^z &MBtt4 1c`Xv-&M Cddf8ȨM bAYYٍ' 1_.FZuM&BDt:Zu ^kr˅ӧOcԨQHNNwߍ]vaРAFGGn](ܹs8tfΜ AТE 磨={m6f]V,OL&=Ν;_Y۪KI$_C?Ɔ h xQk2u=ą PYYҥKϗlp JJJpl_N}|y5͚ ԯ_={H닋 N`֭Xjի(m/cp\x$>4n oE~~>.ZЮD[C`E cߟK+KkμlhҤtJ9`c χ ~;v ݻwG~~>.^O>X,ǣW^: Bt:***p̙qפO>ҺdEko߾h\)а _5-Z &`SZZiӦCrr2>s,[ M6 /㫯B~~>&LL^{j:L;v`8qڷoAPZZ*]l6p83f`޽;ƍ &`ժUСF,th޼"65LoFKu:k4(_e5!Pt99`%D@soߎ7|ˑX[nܹsqqqXp!t:.] 8y$6n܈;vx] ;t:kmj4 h9iii8z(}Y9cƌCлwoDDD`Сx1n8$YӦMܹs1tPСCK/a…@p87;N8\.8:mr:dg :߅+,@߿Æ -܂#GbΝhԨYkXhñyfk׮HIIAjj*}Xp!}QE(,,\`^"/~ .`ʔ)p\xW%ٝٴi,XѣGcܸq8s OsaҤI{9ǚ5krJfcLlÕjMj:*s0`4hH,Y0l0DEEÆ c 7|3v;z^zf͚ 6sÇ#::'NbyOKsQOABʓzJ 9V5 $ROаaCXߤa Jo@x"?㥗^k\EG.//GAAAViv=`=f<#0 xWoK볲tR^3f@^ȑ#Ѿ}{͚5Cii)lقu޽{d2<˝j4z9M6EӦMb 4א浏QFyNX?. jyr/_[]Lk#z\!zѲ2hB;l6 8NDDD^z̙3Ѽys 4KAHLLTԟ&MtdEӡ& k֬Aii)"##9Gvv6Faرؾ};|A4obbHLLɓ:1}M3їc0P\\\kM03_pev{Ƈ~FaƌXb:7bڴi0ضmJJJ QPPl6wr8سg㹗=_Lk;Gqq1RRR;1lq$,_> \.yi]tAVV/^?xРAjŮƝϽZp ?Bx+>"\'Ft={`6lڵkoFz9s0c `ժU9s&.\0]pa_('oQcW_r/ptt4.]Ӊ4n@4T"n˖-9ǿ/wށNkעQFhժr]vs}ő=- D+4#NMb՞p@<Ҥ?mܸ1/_*=; H.nf\2`_?rQ>999HNNFDD&O ~?$&&GsUgn(s1x`鸭V_ ƨ|͞cړ<}Z= N,׆N< F#FbYMM5B;#.󑛛{fIII[Ɛ!C駟bʔ)h۶-*++1flٲv'NDTT6oތ3g`ܸqHIII=CB _ XYkŸi̓r$+7He³N 6oεkW^y.KYfI^gӑUϋ/áx87z?ѨX9PHf`_ShբjcǾDZkM2\@MծԤ!w/N5-8ToSgh_( &=/'3{j]ۆfr)ҵ;PPP q`8__ܬPYYyck60\3:N'DQ&Ej2Rrj֙SZZL3 j 6[ni0U Ԯ רо}{yCE\ajl<4i.@QVڵkuhG}-3SF V5Yĕ鴯ۯlN } H   :MwuDQ7\-Gsg`@BB p`Μ90 (((E1i3<6mڄ9X;v>Caa(*++gyFz]veeeZ_>̙2 ~ԩlHNNfCEE'***{!,, #&&F8{رcѣGk'Nܹsh"7?33πs.M*99Y\XXEwd^1sx-Љ3s>~xgqQX^^{=>uTEQeeew<;;\.^\\ϗ/_2\?#^<##trQyvv6%K.M6ݻwPCE^XXΝ˟{9^XXuw=̔Ǐ7o,-۳g?~< _Κ5d#?[rvx; bd VZm/yyy6m7СC(..1`|@߾}yf1={= uСCsܰa8t̙31|طo:uꄹsBa޼yXbEܻLdeeO>x L6 :u޽{uV8̘1;ve,rmsz 66/Vܿ'N^СCtRsg=#}\'//?< e˖СCX8t:'`͚5HJJѣWt#GA~p뭷"..C AfͰm6t :t(ڶmu֡[n!1{СChҤ .᫯u\Xny4j=N:M6ahڴ)[ 55WƐ!CB&w~zL6 iiiغu+rrr磬 #F@^h"4iEEE1`̞= ˆ#D(_}kX,=vFs_;v;wlFzz:N0?"&&7tٌN镰:?Qbz=v)?~Q8pv*YwƁioSeǎßg@jj*v%=CLL bccT}F\\7deeIPzIK_JHH~+AZZ\.bccg;v z+Yf駟pa7i?3>N:?P|ںv @Ez,툉bZ2al6DEEi60LsHJJ^EVQQ!Gbp8eꏫwDoՁWvt:XVDGGK/3͒7T^t:8N!!!A:f"%v;&s͆fE;p~`[= ł\ 6ԩ{`…ѣz聬,㭷Bnн{wǒ%KгgOa6]v֭[QPP7x}EIIͤ$|8vكn ɓ'oI^P~~~ @_ٳBZZmۆ۷m۶8rΝ;+Wnm݆#77|%!wll,JJJpڵ qy~ؼy3 1|~ի ^C^ЫW/dff ,j!<:u*rrr#** 6mh]w݅޽{@DD 1cl6K{cƌ^W᷶i޼9tѣG#>> ¾}uV@Cm裏"##o&{1$$$/DѣG<?~<ʐ0L2'NDqq1luVXVbԩ!F_~e̜9gΜ5k7}С6m#GEܹ3\.n&5 5BrСC5 )))뮻 ǖ|=g p*"}7|p̛7:snzQ0;s!A4 H A3GD0JAWH'7  kA\ ?`D B H  nLJVFD0 u z nX<  ( ѻOh}}\cCegeýǾf?;\;~/w=sqxqG*)yDiq\!}F>cz}NXX={qdfpq!V2z*qS:.-Wn V&>j V+ϥQ}1+3p?3%ʞEi6bȷq+Dꢞb\vdג{THNCJoS}qUS 0EE1U3c{Ԭ1 Tb?L&*U<#N}mz;y}vLu.LqUyVX>jdLUOA(ꭾdϵg)Ώ1(Vu=-qYx:6A@ Au$ѠS$YqONԒK$,FRxh$,ۨPۓ`s .'kBuPQ_Oޱ!%(y{y*5I[uJzw4S/'դCUX]F3Uza L p& S \C::BA \['`1^` 3.DQ:I:vťS%L΁)LY}Y"Rqz%]e$`/1a$qyl A\\Rxfӓ>qBI@    H    H    H    H    H    H    H    HZ꥓IENDB`mldemos-0.4.3/MLDemos/icons/display.png000066400000000000000000000245331172143270300177530ustar00rootroot00000000000000PNG  IHDR>a)"IDATx] |տ^BH.k ,aEVbR(_ѯ.Ԣ"XVl+(HV@ddB6g^wg==\KUQ&B@]X@%*M֛^n:+ȗ|}*utiРAVZ'N͛7@ ~`&h^ CeLj~ںukբE UF l˖-tlU۶Ɂ*Ϫ=1)Ѵi4ꋍtF֭[ULL,[ٶJ cLBBˆm۪.LG#h 6ԩSUJ/c,߼ys^^2VG&)`'OVDLO1VZ}ڴi5kƌ,Aƿ#U+{-[T8ܞ)TGݷt}hoԨn1n[@~!@8^?vn&#n47Ĩ^UV ^9PcUPDLoD/tL: E :v +impRSSKuJu4=j{!@ ifr&}nW"ߪm۷<~oEuzIT@$kZ47 ÇP2ݷ5jh׮ϵW}+0amӦMs'OTk׮S11Zl ҫE#1xGʆ'HPzu*uPJ$b|rf&5wڥkp??۷oڛ_||5|&@j^A~~3NG9!Uvd?F̾;vOF =$MlܸQ?q:  Aѹ|MWy$E 6FD}3 oQǏW ڱ%! /*kXEP42f\ Ƨ)} 8*qztn`i@8uuw>(gT@@Ơhܨ1G4x(7}Wo4-M};g1#̀F{cmNV;iC6~ߪvCY p|$)`88J*% .*h k~B]+=fh-=mtXUxӑ2%54 Z(~ Q^FklLa:0Ӌ KH4bdggCj07̾wd6bG ^,' ʶu6\9ɑWfCƁ ",y` *cر={vsX}pxX!7nZj B ڽ˟LG<~(7ִlQ_2+7hGH ^6/ fDQù-F&@/@w[! @̆aJ$BD% I@bbpZS3&H4ojA3j\TKx Cs EVf!Zi&pk}L6hE'oî[̓;53d#F`8^@iK ú? /@l&}3g'ѱc]v{L-@H!cCcd4CM},#QĬ,+L p6@I ")J}ݧ߱c;{1!/pu&MmRĤD-9r/L޽RSkYj_>2澦c=wt4:.Dx"0% p 4#?^'U?:^y2Ns^  *t֭+z]1!uБ8bѢlţX-wb% NjR8x|mqt-7@6?xZ{@dŊlH[6 Z,ߚɼD7˝$ bDf@y" 3$) ?"p8_5 D/_X#u7oW6Ci͟/B5%+C<2Zsf.Q8b ^DrK@87{Xw/IwX: *Q4m6D";t؁o0!^U;j߾=wI\%  ,nTR@FWtp8O c_ڲyc)*$Yv D6} ~-IjzhBD * $ 4WLPS R թSG7mlxH7˚5Sɰ$׼޴q?F֮_AĻ1) @ht߼(  4 @$/"߇7 s%r1Sgv!]6E%DH};/Zypj早Զj1BF :N @$d *|Gjt-7(2mys\,R$}-_L0hV9S%x`vy 7$ 0z$>26s![2$BBe$Lb3ѩS'7gcHФJmolX3 |qb4(<m7L4I<$W.`%@O`2ȹ![Y/ 0mJ_z]y%_h:vPZ74~bFiF`i0M`t \*AFi ;Ô2e  S?c]2$4,mݦڥ+IO In(H@۶AE Ї@͚ z. 3! (J&aދ߉$p1kbamH ƫ xms8RB{:9yІD,]9-\gV^/0:$UW]^BunSg&#eSdsLw!w"s.-_W6>8>/@JXJJՍ<%Kr =|+@Y\Fdɘ@:$!1p&,#L =0#O֭Acic=VX_vš\1ԙqQ_(ݥsg6k#zk 0 PK2fN tja&4F{`^ PD{C:uTO* ̛T C3_NΗwVKP}P>@}w)1`$0n`8@/3+X@ȌW x'lc] p%2ڰ >C89k}$ןoo#P*,0evMv_@dyԻyI5Uu^@"99*5ѽG:b#p@>Kfd 7lPnvBD`a%=׻{&\ pX {:^ѳUR1`sYTa5P=lACHɧT0c .sQZ< v Dm@ HU%%0xij5l膂p0%3L>D)abUBv?ڭl%| 5:MhÇ@FDJq0C&X.e̜ڷ?C-X:ObWP=:' K('7'HEt!#gjGٵ4E-`D =t( 0s/u @"#%+Ν.WW_}ZxW>[ೌd4h`6~-V-}w~_03fK/gsk_w ͡'P]tQ}S}H509}7nٰaf0_D_jE>@"kI>?~ T@-ranJ>}~="eV.\H*) ` nͷR{"7pf2}3C0<6@ΝU﫯qPs(ƍZ%yӜ9sxJnI gT֡,oqyu!w ФÇg+u d+'y%_| su5ר?@~[Lhp,59 `e >:f<6ȁZcr p"7>Й\^{-;w./F׷kێ>n=G<^xr{H8pPhZx|Ua\wݵ l,BC@a|e@~X`/#4` ϮBUC-[8uksX=`+/ %ݺ'q?QpHwɤ3w#XAuU>O @ٳ]/sF|'0V'p ׳x3g.HV&ɠxE70-q(x޼qe3UoB;ׁ~k:hۮAdPe#3/ < 4P<^h QV0 tg eҎT@|UJ<>qsϺ Q^~'=wW(諸:@YUp@=7glk;uzG*%>1U9} MpM\ S m0|M,eV,j pXʋRB eq6T$w٩S Eу$@_^kX4`V EF=_ .*M äDM`Px?G{z9laCMUNFlŗCz_K.p_VON@by 5;+0i2w^a.@`u>tM^A2\o}9y%2Y%Xն]tʷw8%b؁Iȴa0 rN+n?~5%l #̞ͮ$ba݅oA`ߜmB.r=޽[_4w=Fmڸ=nꖑe(FHbء=SHI/SrIQL6fH_yZJl6Rf*g 3!8\3IL)o! + x"9/7^Cg^K鍗AXh6=4nGET#5&M@7$z(^/@:d< U.,G.mfKx _]`6"tRݘl_,ƨkە;mnrIL岸Q-7oz_u5ŜO|~ blq}oqjժzX{_:֌!-luAGlm94ҝ`=Ob;҇n쨜$sc5nG[s OK _q)!9^b*s?bbȈ~UX  ,8hr!C\8Cooij+Íaz֭3݉]7!t#6nGBqwwti z[ T3&9F11hjΝը䟾+\һ IMDECʚ61g ~:̪0٦W߾BppeBqp^:$IB 9օp7\y'ŏF;Cȑ@bvCG#::QT1AHpridJ3ʭFX1+ϽU[Ka\+L1-sbLUJ& ~H}٧j6ܿ$JUZufzc8m/Paژ^ӁE:Z{,@*4 bgMQ6뱛\1FthJ!"?I/m/ض+]L֩ڳ{~<+r'Prc͚5KUOp ZɾP@ ऒ |dF$Nz֮!IǛdebv]7c) UP7ǎe_z( @@4;Uѯ=YFWiFl}8RzSԁ%*.\r挙v !T\P!'Qr8yF9Dr۝qaۆZlCmU!EFQ,:Z'S  B3Gu|lDV\ A]g!%Ө9}}?3bPZl\80z 1ޙjx^,q6l819NO9@Bɤ3h7QQC9>s &C"O9\Rرcp;<=wne:O>iwn)+G  ZA{gR!xߨvKv|~tnGEE9ujK4{1_wt$-K 6l!g1t|ago+N<+sm,P C$mzNhvH΁oXK_n^H!gG<<"RYa9sAPPeuuzhGy!xZ5lLI=˗ПQ&bF'[*~e#O<5ѱ^XKh6F̯CLXLn GIZk[ Jd %`K5!̗W٤ID{8yg?{ |=~`ĉj˚K#BHwAer#ȣx w?=: /$E oFcǏW(l`'BΘ`:P3FILЌAllU9:nW#l #F] W[hq3 30[W6F 0GO7=:h3CX}Hm nZh8QPXH%UHZx0Yʚ0h j;-D_?~hZjaMtjӱ|mhԸ7.&N)&Lr#yԆ ǨD*aG=BuKF%De1<3›;wqٺe0,W XM`y suBG4@E;22Mwdb ɨͭE`@@0Tigdӑ@=҃cPlu? <)m.^к>A .&V%LD$`#G/T*@7s e!z;<1zQLv؉n@i$״оLG 董hQZJfߺ #5pbd+w8nO :%y?T);<Yk_EKAGJ *rA^8IENDB`mldemos-0.4.3/MLDemos/icons/draw.png000066400000000000000000000543551172143270300172500ustar00rootroot00000000000000PNG  IHDR>a pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FNIDATx}wT3{e鰔WADEQCbI4أsM3M,b7*t,:;)3&s=S~j.?{g_կ~Ai,KMZ-f]AW?di$/gYv~]]ׁu #_{P]] QZZ oD"N|$ izIUU)n9rd9f[nE~~>t0Kܹse˖yN&H?&[n]|K.O_S dP]|'` !IXg;p? dQ(U0|cSjkk1qDDQ7߼677C 8D"1ZLQI.ܼyKKKϲX,޽{n͛U5{45ɒڻVMF"I DG__ FQ| 3gco5.r`ZBVwF<(غu0 `Ŋ<⩧gڵ.XL֭i* n޼oR߯]o Ḁʳf ]]~ G4ti999ҥK]Ay+**"gDqq&L@$Upw4Mk,p0 y>;vlIfϞ}܌3cǎ@@q}= %,2vlzz? 7tZ8p뭷sE!JR]]mkkkKoݺwvv9… Q^^ؿ?1c qE?q ^ۭPhNj,Ye`%%%h4zx(. @U>{7Wh@`.IiӦ'n///A(%K1bwq,X߿_~9:;;qmW\qMя?? s/+WZ_1xppвyc^b7E#F\lfY!y {$:tP jpW^p5nl6oC?IC<Er088?~|i^^BQTr)QL~7$Is踁YlX(>_^=wر/^? QL1x:\SUU7bǾ}0bYyyy8|0.Rh^xP7oҥKq>T-^ed2nk=S^dz+^}5#F0{ɶ Iz >v$Q<ٸ%IiӪzl$q HRʛ$ck 9:u7|T ַ0e#<-[`Ϟ=(Ç+WtMM  b9tP즛斿O}'MP(O*#az $UU}4jaK.Yhrhi`~b Iib@ڶm[l̙.]z0NرcB>aٲe#4 Hltuu[oň#p#//Fƨ@b?a˖Mǥ,hdRx~*DI999㇈ѣG477p8{4) RTqEQ~_jmmݾaÆ7 ,rssqUW㭫+5Ess3V`}Μeea f9900A,feB C:"I"i0cƌs9g|NNZZZ}v pCl&gy%HII_n喷0W8p@VVo߾n xёںukk0,PnHa 躎dRsIųfF<."L? M`'x 7tS緿zeY$:)E&7D3,n]veϞ={k֬0xꩧ&Y?:Bf:~:;;;}i{vSrssX,XkCѲ(疔\fB  0ɱSH$R4MYOk?ۭVbWl,G ?\7̜9)//?K/űcQZZ;qīq9vQ\\ p0LCF^hʔ)SN-Xd }W`7|>߰ϗ_Je˦Ǎ@0GW4iBcp0IR4g֧@uA׹ICp|P7ę% aÆ 5jZZZՕ`$;w>ӳ /i۱w3s: &,wCL&5kh{G6G~#A@ g{nTUC4ʣ׏^/x>ņl+EE8̧H}LʵxE߯ MӐ-*vϸ뮻@$$xISLYzȑ͋-p={z{{9L|_yya7Q{ ~kvݹ JJrDp=Dbu N QTz,)ЍGA! x8H ̚5 C9Ár&Mx˲=qYgUUUMD"]BChjjZee%BPi"$IڑOF:"(0, H㺦oP,@CW8J9r IM&>l|>_k\p' ֆ_~z+t:^ ô[Vخ͛7)%|(Mӕ/IRεZ͗L: rzc"C K#4M?T#;ԇb'D1Gƍa6ݍ;v X^( UUU8{ʕ+1o<8p`ݻ۷ol߾}=Z;~>Z^`ey(~P F:g6 '{2!:lڴ <ϣF|Cd2 f (P(>b84MD4C5D"Jċrr) ( yyy˲8|x7+;wF>g31e455W]w݅X,6s#'#uP=><@2PU@ԛ,LOPTJB"!˃AAX,'4&}^PP袋+7hkkWU ۈ5 c JRw畟uV-HB2AOhd岂|$I^>uL״dJCy6m5k0k,5]PP2e(M߳g*g{PC …7}?MS4ϟh4Ռl3I(4ةbkn8?rHܹsx6l@ D17t;i$<3 4nݺuJ DK='V9,UՑN+z0_7~ V==1a<65K~_Ξ=;m6G͘1 Enn.?|[KK7=%%%=?]}i>Oa-'DQA,BwwF`6=)L@7w~ )**"f0nf---/~I&j(Ngo= ~8YF3Ӧ@u2|0|FPU ,kn#VixS$AGA?CA!`o\xvpfy(;˗/GAAe˖1cLذai„ 7}<dȲc6 f#;Q h٠FCةT?JAi`Y%%%X@s$EQ!رcPUE^@2iٳ܌qa_kjjZ@r׮ߧ򗿠:pb'g=2c`j ;ۂP(d2cY"L/ En 0gX,+ArJbƍpp8`>/zG*nndY9s&.EQݫ!}W^lٲXX$"]]ߟI0Y0:cQե/BR*8..?D:XÂ" QX:F/OGPQQY ضjKV+v;dY0upGii)n7>[]۶msssqY |zjqVUUU8z<pA)MH$*L8 `?dƄ.IPU $ߴpzʔPU ?YVsaV+#$}ş̫ʂjÓCry(X,?h"ѣo!jcYxꩧF㏣%%%}B}}}dC9d D"D?o$a?# AϚp9S0 DQF,&݇^DQA`Y\.+JJb;Ð{3! ެ;@tŊ{زe f͚׋cڵ>}:o.˝G8͖Culذ7oݻ-P4 Q2~mXfL_U,+?\h]SSYV!*#"BU0 ń"X@OO\ung ]A {7x#0=#.9͗^z 999+a(zoooѣ .󫫫xh4*7$}bN o^`HhF3?0G:-$ ,l+,yb=MϟO/Fsx$y(J>p,_re3˲/<gYBSt:ߏz Gq@P>aJL&I02š^#gFܰd$A%tuF φb;HAQ$΄B*gd˲hjjq*++G:too>cƌ[.\UUuS]]]}-[y0 |$ɴi7o+YɄ]va`` q\:~|H++,MSHI AQ,3rs-(,4?h4 ˒g"\uJ 3u455+0aׯiyyy[ZZoYYYe˖zq[WW (]Z:qw}t[[ܦΝ;{ 7\8Y?>!Qh N** (i]]A BQ$68V! AM~"D)QQXXAqbԌ5Ν_|sJd׮]b:5c:ѣGQUUe100@ kɩw8s~N*" co=i>3!ʼQ3fW./ RhŒeg艄S$IkǼ꫘={6***Ԅڼ}{ѣGn:L&lٲ%v]]]t&Lʢw!466n4x$D"UAfH@j7)]ͺ:oXzĈ"hC[[? t]aGnND"D=M=^=􎎎R)v!IҎEp\8ss!;;k())v2HpFc7tɈ.^00L=~e≄(vƌPIR'3feN6,$X?U~aӑ#G~hCIkwvtt3f 8;cwށjEcc#N Պ;v~^}hDg ?Qy>_u&OC4|أˋH$ DNN $~9G}K ̙ô-yZχ)S@etttફFbooǎCn\A瓆ia޼ yYV8Ϟ]A:) "`[tfD?Mf$I}zfeeݦ*BhhhKJJ^8e;7oFgg'bݺu^9 ChsovPUIcT@u$)ttx9p8 \(.Ȏ|4Mx$b``ϧ@4]z# aXd ;w߻{ǃ۷O?4^/. Q?DgDb._YVZ,skkGj5Q8zzzCv 9@KK׵_*qOCU <OΝ;t:+`ݭo a[:>^[YY>ڵ >n7|3l6\x&A q |y:|4M$;~|kL/L/bL$)((r4aHE*AKˋH3CE?uAHVVֶ7/ܹ3ܴk./=}Yb1tww7ފ_O?49l6q0o޼ZaKyua'WBIDNa@Ih 'Iq qf e2qj#wթTYf&IRY✆;eٰrJ̘1$(hmmMwwwSȌz yA d?UUBpn?"QByYYf'&_4qF=AdB⽽ ~6!;;׫WAkk+;3 F̙3'?)Caa!M^^ EKPVXAb1a``@P($ERAGN4 ;wĮ]@4ݻwڢ?tC6}LvmUU9/ EA*%jȅ2z{#@1$OGQfDhiy }"\}… _/++{p)))!{& lr577h}v8pwuOI\,Ozq^p\cvP&=N"N``x<t:1rd6Thj5c2iGHPX/C>YQ'vڥΜ9޷z㸳~?u֐`O#,=ۺ̂HBq`wpQA 2e 6oެx2(Ն,+` pEۑ\#$vKuaaAD pAyyN |"!E)E4څ(iOi%hba@___k'$I( /M*!E&~ M\.;R)4mF^^F~qaP W\qY׮]T*۷c׮] 577BDnk4Mkh#jر5=Xt@48}\P]pXvF N!HMB~nwXz$wjGٹ񔩓:V2m4M6m"ھ~p8p80|+/Ų,ax<.*+V_PPp~EEžh>t͛7_p8 vFmMo5kҚo~2(CСHFu.eAQTtuTUT3HkS?t0i4M(O<̙K 5556Y!UU% +Wz\~G_~9}Q!tʴi~6o|3g0t'Iv;X{iJ4hdY@K 8WkMJ߿ àF>^oh66>b:i^{KKˎH$7 }om۶_1=LQ{ψQ(2i۷|͋&LÇC0˚` I"zz-xHҫNȓ Hд @3|'l|_Ѐt:|y睰lE"3<w\ܹs-C[oٲeҳ>[^VV îƖ-[`$ LJM 6;gϟdy`mm(//øqEJȲ^">O d9 x<>oF0k,pgnhh . UUUӦM tttd͝;7;]PWW׋{/c B4 u=쳰'_x1iv;$|gMfJF"b( EQڊH$ MߖH 3qhn~<<>i8p^{mkyw߽{Fx侾xnn󡨨ߏX,Z̜97o\-[t ؐqK&'Cܹ٨li4mQmm#G"L"J8toYYTUACCɄXo6 0`:#?%hkkl߾O9999۷o(GlkkKVUUo&Rك5k`G=`Z p3#Сz  1M ?>ǎ;vw隦CwE I~vK999m2#G 8矿fĈ z뭟uӴix7!z#~abW]uIB!;v . 3ʈx<H$ Np8A^EY+ST àxpM r̚5fʕ.rsqq1oߎH$g}> ֭[  d̽+󳳳\ /(k׮7_h?fuuue{^|goe߾}$Y|gOIIɺ{キp\9^zi5˲bbF( P Ij3A|R "Hđ# O(n~\.իC,X?OشiB~WzֵkךΝ 9ry``9dڴiN GUU,ݾX,8p b=zٳ]aÆ)\s{ |u+A9C(^#;;t ==8.aZI#W_}@sr4ˇm ?vXY7, { suرx}t#b֭[,f3<1gB!H$/ǎ;}v /ZQK/_. ߿߾F: @0 rrrf5MC> @oob(v4MGga$ۇa}={<3' )S g-SO=bbH;vvwwgS744DMVH$PSSɄ[`͐$ ~cï~+pl۶mdi_TTd˲J #d2b~ <>{iӦlfv֭ĉ |{EMM ZZZpȑH,!o~sV EQ?/͜9S+ͭXti ˲% :$)r]wNg?sY>}8$CRbH&y( ",ADoo?EA"H$×taxykđ)w}uUX_v4eYv}}}K/$|8Nq.WSYYqٌ3H$T*2EL J IfsFL,(͖Q gs =DLXÊ^I9gpf}?TC ׯѣ/wͥKnmƍnۉk6޽['B{ɔ;vl(ȑ#(˲P(3j4n\uM08M$xhd uꬒ3&8qiHh)#s3'8QO C"6ۇΩ'~05t~#Għߟmu=JTYEQuAtJyyy^4Mh GQ(XQ1朱c+&N:.lfpذ|B\x"BR)UU%={&< ۧ:fL&GWWbQƣ3Dљ.waÈ?2 S;>yN 8. (8z(E]c3NE-[ ܿl2=Hh$)tZQE!q "<:麞L&ǕsL%]DcǍÓ={>ڏFL~Ex$wMabbNeIT*OR  AtSE$/,uȑE&L@*I𨪌$qa/hT@}}`Y;E(Z-4@DQJok!3n%5L?<4\岡n/Ep H4mֺ N>oɒ%y(lF$QUUUeYVdYdYN2KE1|T/=+MMMeY6YMTMdata4.L&t hx\M$ABqqOl6cH$Eȁ9aBQqD"4dYA&O,'6l>|~l6@EQ]iYUU)#1Ľ08~ߒ\9|1wL2tؐ=mmmv$ UUR[aad2ŞJMhe~_⮸jˍ&KD3"~Q|D1àN95V /U޷oo$#oiƥ(NQ*B2 ddN"&ʅaNxaP>z>IhSn<ܳg6X,VrL^^[VV3S4MnQEIӜ owvv_j9dEE)|AbQ‡ $dYEMw(UUe=k>D*+*I)$%AD<)roU{6ΝrO#Iw4NSI JBW[[\`x^ZYY(++ηXL$)uU4]D Ke˖Et# !"# 2X8ffaԨrdg܃^xCllWQ0eB("iUլyyyq㑗  q8 2ЅlfAtsT߹>ӛ0XEXQUC!_sooρ`0hSt`;4 -TO .܂ SC{4MEQʓeF~@ɲ&4#IdY6^Z:e4_&EN lA|_AAEaXn+TUEQ<6eJ(@'IR@4&IRdRb*qHѣk)/II09'IQd6 h44m`.H#GEM@QW&n6jPE"A(Rg=_V8ssKT)$c!ġi҈tbUx0W$I&XL`UUTU4q7#77l'wA 7P iM4 &dYAaa!*\..gLc}4݃~C8MSDGG'ޯj}#,cp\@f'1~,s"3s_R(Zee_5$@Nc+2~ I2fΜ9xk`u*򟽾r"k-HIENDB`mldemos-0.4.3/MLDemos/icons/dynamical.png000066400000000000000000003106201172143270300202420ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxYn˖"bkW>}wy*d%l 2$@2c_+~;gOŧtz:qh6˟pq弮~i^1qyq|EJ߽8۞LZyź: gu/ż\[s:拾,i}!m?k_{ (֞ i{3߿x g{rE0g֞~932 qaXk/xȳtn[Są{ ڗs/*S~N )^)^}8YQuӜ{?Bx~Ir8,{ZpJ3gŅwp:si>oڊfEᾠ!?MW?4K p^+sֈx!ǜEqM03kUɃ[dyMן*o??zBg,A^u6i.ʐaxg!9t_W8K@U/`Yf]ghpL4Ԅ8c* .YB\X.Y:|[Q` LRPVy-{<'KOY5$+7Bߋ=:֙{ )8p?9rķS gϙg6g$s&/\t^ e39"] >=G½>K͞vU潽L~:3$y 57,qA{.²8 E tkfIx6amxu,+JӜ μBAVAy IIsU @~h:/ B7^qJ}Z+@ Ҝ~gT_qwI_/Uqka/q gcZ1S/5}3g"/ѩ `?8 +A"wpU嬰X.%Ҟ]ZrFD\`޻?s_;KDň @ڻ~Gw]9{8}*ubO8aq;/2 /gg)" [k7/΁q)8Ewg}I+U()Y!Xn擽C|9Rȗ+)[^/,3!\g%S~p1 x|Jx) p6 (%3ޞ#x3Y{<(_8~ izZgZWw8w.ڌ pRp%Rq^Y7q$Qx?57d&u9w4t;A7Gګw6;VzC%G+A|Kݸ p:8Cf.AS| \ 뜆./YrΜιj.g x6dx4\+p&υ8( Wq+sΚ抌Kg$ p ezYP\O ^&p6u&@y񭼘[pfN q:tSJsqﲹ&=ޝ^)wwZo`Уy. ON,Wp]g %x 2R`ekcsUH,S92g,%3B`8?_MK/`ι$\d\ {9{#&i p8MWe]<+€ύdYR9R*f ?޲%qKt߯5twNZ]y幄 _;ӿta>Hu>3 c$)$<Ur!x> x)Ym.S]3ry! p0FJ@r ge^ 4Lgy^ @^ h<~??u\<=ԍ`eZ?xAR1+ ,aD8 ݗ% @/#/Y|9p\%n˖Y⪴c{7? r*08LKҞ ]"ϥ/j\ !iSeϲgq @~v*%TėgDO>浻7L4! KS ﳳvex{K7A)`suH4Lfs%.ʊdL*pg3/I8WƸ`ګR[h)^z}(|D^_Urqԕ,eBky^ ëoMWnTW ]".oWDp .sUUc]OpENå.!+Dv6/DKNM]*򂕵[orw#W4/ڴ.oI*XcY\vkv4ehKM^Oa[ |ϼ"ݿwunW*sshIHҫ\o]'gϬ/1WX?G= // $eDOϿV|QS]kŗ/*/._ug\أ*unnpݮ5\vݮ]v ]kn]un9ϟ~ X/"} Js_O˯O~q?}>Z]'~B~*XEN~y;}/K`mu^8`"_L`S%|QPC_8S?efW˧/yL~7O7B%vK/rWo%;V6a{:c?C~=3e;xQEYPOosVZ~i?9-bL۟ngA<BWyY|F#<3XiK_myTU۟c@4AU@PgPzA5iX00 ewI"n,X ڐ>iU.D %tra>82Cwj`W-?/X@ 0B\Т]HvaYqxy_JV=[q˛bLJ Os eR9AO{I͓fxN  ʚ ^"K`B>1LNsЏR~Zz(-оJG|NNz`|CP$uñR8|^|n7Ĕ]= *NX][g,dbLh "WQXAٔjTAr$CL^]`W8Ad̵ͷX9+$r'kl$K( PV} , u.zՖ G^TOYmRyj^ksJSӥ3A;4rK+VJfy-r 1&=j V!IJPYjl;fB), l|Km/d LEڎ*e:ym~e 7d8552>Q${1~HB34:5d5U j^8ı=x>`-(F X ZKVeYg,dw\l2桷Mbx E>% },~(ͨNxBl5 kM :`(Dz֫9 BQZ`UUkDtLI4Ñp tC:uN+ih/ 8kRچ1hJҺ! d-A)aP@S-'O7zV[ KҺ*m,i]iv1Z/qkm{ ik+ZMf P7.E]y0`jpգVhl馘ZW  NškȲX Eg*U]՚´`mLB3@۟nA/0g39E,r;&O`cXx yĉ[ӈ;Sfr,$}ZF{ Fwƃ!I'[5+7sRARj͘tLqt%M3&NS#2nEcOc  B+m 뎡t|F}6F1,5dLeN[5][ vhY/P?] fn"/8z(ASJPXhˁ9KUT HGĦ!5\[zUFߑhkۚ(2|fgyj,OMgmZR7Bitq] #Zaf5yqiZ)A:K X²x8gi]-]::u N w b 2ҶsUK|4?5j`)ZpHM͕9`Bu ؃ɼ(U dUt֋$"$0[J P@ހ )~xG?e}V ;#L}-4Α$ؓ(Q:uq@pr }*`4k"sBޟoqռ.e3y^x쨜2 AhK Bj H l 'uS0Ǐ^@2wvuamY57 5=]"|ȋyS|P)asxTA+ȭpGh$5!n(G(L 3kJԐnp@#[wuj尓F^h٢]ut h2/1 h5u aUSt'^|ڴZ%BRvԒZZ@L%W'0.y^SVKaKP[LO͚8ܥ +^3yu~+/Z^V֧Fn؎ Z**@Ϡt\;a[ɚm, pw%pXZ;ikT<ێip-):{^HtTP a?]9x G'8#s1BX"O0)><a2ΉWVXPP61wBHv+rF,؛eLT K֪9Mw. nxĸHG45wTEFtAdF+5Q>'vQHgDU 8p*R@x. bߥOxvx2$vk*TU%y!\\BJDSHIGWdVe5VH,fkFk  󠜡D@SZZK?]?ܴ0K{k}gũ+ EւjM,,n]xU.OmNA69KjYw[ʪ!ۀZMuPזU;E Aj988yXZYт.[Q/֓s Z+*Z_oal 8/"ia:zT)b-(ǻp2-~=%aScG3gSjyDF*Pr 7ޅ[-XT..Gj(3a10L9?K͍58Y5#59$wńj85yf !v<$Z ::F`k\e*vd|`K=}N ALLO<̋8o j 8H\`ٌi4A=+"R15NȔƩKƵq6$_ nXX0hRHtW U e.44]j5o] U//)k)uM djK49K:cZK T0#\|amx=bOϗ:<$i݅xƷs"^3/jAe]! I[ R.j,=jZXݠHGK+(V,2x` Lt67-5"$ݛ9_Q{@:ȁ`]0 "$4eo$: '::.fuMo|Ӕ]Kσ$qVh|ӈE0YD~V}VUNWSӘs#(S4bOq1MR+؝e &S&Byƚ(]ɾvq@UHP,tI8tצ OvƴYI1} 퉲bH!4 |I_ml4eDE cA6j/Քx- []냄2ɴrYq<mĚS `Sv̵"غC|\y Aiaa;9)96.}S#hM BƝ5gap<7?fWT%Ӗ!]] \iݦ*!!9N̬X&f) ܦGIȖ3dP/Hj 6)/1W;)Js܏!XF2 2:lCuY$V=|f22we0MnX dMn%S`3LGq0n7n+7Y&|Ip3fkԊ[+{9{gC# G45´|lWXnVGt=1eifY9j4-uNɜ, tMf80BAeyK_ d' :Ǐ!QJ#):65Y-ף/4t<,4Iž]OS7H%@4-[ƣB*SCWa%3ucrкA*!o4.O&P @Xf^Td6kV&<ʗY~/@ɥ`OQˆ7%6ئZHcyTEZK^SS x qQO,R~/EgPEb OO?_fětL-ލ6LV}d#29SeYyp<>H '6Md:kXf ۂAT894*n MT<ϥY+1JbA~~-!}{[#~B11ݷF:]̀ Q>0SC> [|FCfzV_٭qmmJ\%[nN Qx[ l9qvA-xb4E*Ѻ۫E hD,ZU53a>]/hA qpYje#t[$Zr,hIoS!$&9Vdwiюf٦E\wbi5ȃ[-`)28]@W#zrFe fŀopKW+ 9v#:>ڛT0Oa-A=  y9'Ưq{yȣ'}YL8参֜T뇳d֍8<9ݏ3ˈ@ZuٺOGcD'T%R !p0۽ |>BtΤ2%vׂxHdTA20(| Oa&tn&EQl*zQ&mC5Sn7|oߜ jIA7+a18ݧc rwTY-=MFgO&yUu:|܄1_*>6=:! [ܸRDj 69z,ڊg?kPä6 V ۃeF_xTkMA3ǁVpu 2\s{lc *khD(*ZEU-]6N,)XtkhKXj9)2q2&f `7 7* ~?pX$|c! rA6:i7 A+ֻYp Y-IT:'cBb>c+4 "s*5VTgAuIώ1;Ii()|B7(>yچr MEh j?`zqN15QSXYuFx"h0Y)5)Od;` mjVc˂88.!V$Z'5S!黂H vGTnDGZfuoj|vrSO裒 OӬy l$GYDb#.p˜˄e/ī\Bp}u BVm.hc-$oÆiCnqiJBp2(jh1Jk8݁+"`֏_L[(w!Z?n04ȓfwgK/KɂRqSu©q-aV#hUы\'2VjHl KEDsXX-X}6ބZۿRkK\CgCbl5xy{aZpՁqϞgzbހXYnd E'U 3cM֨ORWclfx9$53a7mQdGM"f(DdT4<|xu |xJ֠݀jSUfl$ek)SLTU85kJ'3_ns#?&s2XmsgH6㗿׾ϛcsLj><|q2uV#KY "nV }xn@(e.Zٛ)S\]%R;~MSlȜO.f̊jpo zy<^u{g4nbœ-WUr\&a<:#tSᚆBSlgv9 ت4~DLCQW(q|LY%,džVR1)hI\]@!tKb% 'y1K-NSe+W$ֶ9Zc RtRG"LKEGSkjL 6@7 Kbnw ˒Zf>2+qp)M3<P昲qFIܿ_->aFx.V LanwmТai5estP :0l aѕi!pM'vG5-(8Ƚ>laJNVq"Ef DyFa]$`۰G; >0O0=__;[1{Wc~e?yvryx|?U>ûxz]`!p14Gƀw7in18IsD5KnH[S+"CeNx-s2M~v8g8$B qCdƃ˼j}EQk^sJ*dXNRlp]SxQ~VV`u3ۆB#.]q vY' W0WR 8 mq;=IAQjCͨJ IGXlӐvOà8Jji_i=/2Ͱ2V6\g no"ye,Y"D燨0mZL>|!˰KTE+}hOeYeL  ubO`D%iaߦ$+tV: 958ѯ4;[1ۨAЦAˬa=׶ Fg |Hd UmlޣLЋ3&h:dcgiW}KޓEqNj~!bG+A__yʹ,T^.x5\ +aW 4 `@Nc%s}唛͈2X`/3Iͨ #ml(dd^LQkTaS<1"{#-1M}_IX4:%b6aS""a&3jF.v4uzhl/@>&KZ0?0DucdS#EJht G' ej?7 4.RjGjk) 6Nvd4=C迏.Cc60S<ᮁlչGpE  Z*~s㭑g+HДi8ICt@#'Cv <IQk|C_L UFpY`mdpYȘ7GJdSD8IZ=w̸gI^ qur~D'`5 UuK\PPʏUUk帱j ?fpyu]v$!N@)@viF8cKZMǁ, ̤TaS芙q^0!*1ǡ~Y+ !mF[2莳LꅸiҔ%DrsZVY{cqtm?ы [Љ^VBAUl=Ay.~aEU?94G4A%9ZI"cjEɞb-NW+ֆ+ۘ/{7~-ok0_PĮga> ! d1Sp-xTF04l) 5)Ecqd:?qרČ {|XnY q>fdWTxJ%1ߧOa DC'xV,*cEZG_Z+i4NquQpBMvb0ٗ 2H2b_&L܈jj DJP44_-ԃ5_=J:NbDS!ǻ䱇HJD4`r[kQNv'!n O&F 2M[Ev:~aQUXWbMZ-`_ZT%v7KIBpc궖Nഥnx"pcC?ew3"í-s:Hk: ZGXnv?AevE\+Ie'Z>w6?$UPly~JnA<# [xЃ;CÍ>ğ-3=$ak`8YG?>z7_e6vvB̽uw/ 5O 58Ō@r>{XNNPCWghe֗^gI2s2{57}K4%9 y[D j]ST5el'h?f<&ņ]LzeŽPQ1j4srÎ/I+@Jьf#2i~E'@NV'sZEfi[ 'Yl֗G>WQS68'Xa"h]Ch6; l+mjsO{Xu=6? A1a=S&Ԗ{2j-]kl yc =p1f 8GPB n@"p7kj 7UbCl$76ak(k!\U@pg=Ք| V"C m0[Hv=^O\]c}muj~=GDt>̴3t>g Ν)y#XOEY:f@)М_M<-QAQwԵ36ī<,EI]U8tsȴ&knȒc|sˎ,y7|ljB9| iBEp4&[ن8dTydɂA跇}E`]øi:v[I tt_-tFðT܏[?5psJ+ώHWI]0dJ{#:C2F=?Bx7WuMe=ԾtY+I;q+M: yD* X2rq<ǫ++5RyGcL Jh vŃCvC?`GuZб q!Ь<] =C"+t/o(a  &Sp|罯Zg{CC Snp r 쾆%a>D8:x XLKʹ%,FDp{ữ N*l0 +v5>@_/F=Y Cl..2 %n̵" 7Óg*:!C rQbCVqQ!ˆv|ұo1lj: wTqm^4R5bRH]="uIiqy_5ܒ ]ay='C:Ǭ֠0fS*5uy4&B*K`J |N#)>a-:cv19rLM8MަP.^?m4^CX>i:!ވY"t!}ܢlA- G6Q'sMcAxe@.4n!3ۜfcp:A %9ZDI9|f̧鐢5s3e3JۍdJ~z(9V,|VL$lꒉ+6bG[N-|򼠒+6cZWޭy#GnZRC]3,IGV9CZL{*ǸxME3dXV"\CZ7AΑa٘$"+\a|]e+ ~ {N7fC6 ˭{5|;n-<{P%3nbi`JG BC(K"fyȆ)f7x5h.yZW~e&+jڊׂnuQ-y3*rEJ؂iP[ozJ#ߔcBiz< ;0PW%:e2g#tPC^x`ASD R4C6BQcYUJGȪzĘQQ[#2S.F!MU 59]!5Xn늩pٰ;ˊLytW{8i*aMY/ ܬ&%#<"cE`݀C4ǰу0?Z`?TqLQxDGnIl<Ӗa`nAQm'3|%D51zt"A ð=t|C8MYs d<{_,.JFWhf2j'9.]4DG5I+pR;Ⱥ.ϏC'5T@hwضPZD!M@WZ"iX :[D&jʂܥTlZlOq|!%c4D9caCMr90yzprhx3? /x آd`J`>>.ʜ((iP;A>3d')ǥo-yV'SP|SIӜ;Gĉ|AB/p#{n9:V5 kf+]pTkk+.d4םư,xF()aqD :E^1S>J64-Ӟ q$`( L5[>UUy_q?j 67QEy&1#Qf%bxa]hJ6~{cDVDq*~VCC'g1=F`2%hM_[) lIW8iVĔX+X * EYqrʪd"7xwesШ .O?I%߈؍*%fs0K2ȡFy;j3"ƣO%]P!tJs{iO { B܏!?hSxļb7$ؠ.z#ÎǸ/=Σߺ~o5kT^rrrpwA<#s N=qƈJ eHdSsSʰKu]Y% 댍n&ZJS>lO(AJɴ|[Pt jLK ǢaMIj]ͦ:!V9ڛaGj% ؤ++)iu$XEUMM0UӲRA`o?:BI'8 ?~αGGݶzw۝r[}!6 kT5OVrk`er4t]\lm暒~CFz rDa s(N?F \5c"þw "O0wLy o>p  SeuЯJ%Y k>=1) ~fo?eݟzuM uV@w vpcX`6؄[Cŭ^̖sA<#;33oí5&3ΗUjp[?g(>᧏c~룷xIVxw$冓Q;!iJ(8XqN(kXm~=cz8^cT̕HEFvHʒM`:nז XhHt{t%(X .zLydy4:EŠ)(/ضNDP@a%7MɤX?++UDHE.Z4'0k7DcS-6lՍ@S'tt!N.2me CZ0N4fAT@g !d$[X< pʪ;g^ } :ߖ#8pXhf*6IZ32Qq< ?9| Q=x_1H+C0Mcɑp[~;a*;4X+g%k xvy]N)etL^VڐECtʝNRRVJ)bS2. -N6MY%ϴw V9;&eZ:TOX (9RuԺ˰0Z$l+M!U[Xԣ=fæٯ+(Xܴy))Oה,DE//Xm f 4V#e/ٞXmn}Q~]1@9ON0=FMU ‡ϑ;kT.GSt IbEUWmR^11tI;' >!8 8]1x{f/Dr3$SDaXܕ"I;?ʙS굂 7o{_{D3oi4Mr(,4U \!]je݁U O%. [HVR;`ǰ֛1-rer DS13"( cOHy~a '1qX7 hZr3P ߦm򏱜KE1۾e|7,y]foZ5i(Nl@P%9l zNm/a%a5c9 BనF17TFJSxQ|RCW;ڲj`&bBHH}.R%4M¾M͆N8=>=V¶ M4Sd'8U'bx:'Po+DQ#݅Af(>y:vCoC,HExRT?cα;\ET_ـE<ʡib^ۆf ,`+)A&1%M'7bRa|Ze Ԉ2tRܖuMQ * niOiA׳e>h)n=p,F㘄PAWڡk|ӕgq**5R#6 T9+97;qtQ~DQ2~k+BeY,r9u^At$vuďƣ;j-fzˊ"ӱ]!”O}C_p,o}B+(-J>& y5LiҫL.z1p'%v:X7yVكq[GH`o(t+d8探XA VHNR887`-~ #/U *xmiuqZ(6v[:QM, \X ZTYIDSM4h-9dwu9n;ỷDAXҡ*{8ZnNfM^Rkl p}坆?9tx49aW037݆yNБ=f1[zw~TK埰:4䄹A&k(gLԀUѱlJ)jg %d<c+MgwBfT}zWi1േ̈́q]FE<댉) FU)8.]SR 7&"05kv \As,}JU!C3TGaV+tZ'NHV$Ǜ⓼Ƅơ2 v|=6qA*dVn%TEFνeϺ5]{p˻+ }8ax`fb~C\Xi& MQ]$=ɈhQaHzwHX^ ! 96P]ti[2jWxٳ)Ab7t[u1L1JW#v)n))tƂ04T7,nm7C*XتoqBMJ:KWD% vCׅ/XSX"-14T2cRv;$ T0 3LR+TbNQM26tb%ӺPl{ywxOǰ"rqїb3ɦYuh}wi=W5A v ͙^Ġr{-R)2ѲK iupKYUtO E˦6g7LU%,$xP,cn^%`` ^]13fFYHp ݀57K $"xOh.o4˂;-<7{N.S}8Ϙ걌[l!UsW\11w =n@Pd -Jgi 0F9i]NtUx^?wb>Јy"nLaq^ʀ4q씠4ך74)ǂMZvVJ)JKx—`"17U? geb *΋ueX|U3h}cz1%q;A6Laou˙͚Kg kpfղ[v#Ul9jc4\sz%\(TŁfg:ۇFfhRUpv$(KTBp~-چA/㐔x,8arkIO8yc3*dCpDCCqMxbͧ4u͍` } YʝIΊQrwQ3S&iuG(׬'pyf-{g{k>ܛ!OoSCg=a#X9OEzxXڵ$,{P#iI=mx`*II8ٞ˿2w?_m:+pc n{*K< A԰8CxSxsM n@9_/qB-UWs<7R( 04aÒђ}uRSO!Pk {Vڳl,CXhXq&=$Y4`xNQ)$Q~;fnJ zYBQMC"Z2kVhQ7$eݥb%/'2AKb"8[.<׸hNX 4u@؍\P ay,c=BOF,[ ږDcw йΝ0tN{xžHήHBI 389''6DX_cZ76݀|Goӊx9B%MZABBd!BOHVTV4}Ȭ%^'i# &)1x~KD a heCi|aѕSB l@KP{mE![4s~9l* wAA#lIqe-&.b&EC[%)-FzE P}COdչYxL ނc#"z-3Ͼ|E׶8as6MnK"O6/97\rCBEW-2o5RZqxPT313 RqfQ^G!#Rd7QGa9SZdT c]pqfUUVlaQP|jgwi Y|Ɛ1I(&'!h iL;4DJϑ'ȽmlpnԾJXCpH[=6Yk#Z 7ؙfz%?) z-A1fB9p=v NpU6j vKPqva`x-r*ab PqH'62 bz(!I|@[f#" ꊼmDG3EjZj-yx@/svθg7F qC[Lt9gD~LkC&'Bb![E/ j _`)5jʠ?@L' h9QGf੃'y =WgCl49't`䙼۳:Ћ#n%c.qLn4{a"/Y *ts.ly OsNp#ޢux,5;۳<٢s3@!< 90`G(^CN SeXkg`K/PTlX%qzqFJ&GÌ|:#Cf#8,*&ABor}(uI:t *U -+֓;s{U\4X[/6/u|5iqDA?+[5.`R"  F̗(CX1 C[[ms 5ڍVk5Z r>s!jX5Z {jͱ%c?};i&+wQ%nB " X x{1ZH$$Ɲ=_gu5ӄ*̋i=yI=H3<e,TQXLor8&_$@H0A{{:=Y[_8qYWZ[װ50O`8;څrvz$P[R(rC1Þ C .\wq ]V=fNMmwuAq.0!(Oۿ)#%EpŒl~D!V!v_Sop0;k[|O}3c^=<$+䩡^-IPl?U轷1?ɩuťKghy|]}| za0,lm{Ob9R5,O!OYz4Weg:9xpǼpYyq?e]ЋU͑M {Oo!f%6@?qƙo.+絓6]!P5;46`ZSY@P^=vC<4^B% M12 E]ԭ)7[F s\9oSv5w۽ -1I,}Dr䄿ܐ^?|gOp{x|Ϝ}>B;zbp^0{A@Xz$,%5XMzYßsV!!+썹wry|ס)X-xjy k5G*ͰӨmpnw?\՚Cw>(c1V2L%QQ3%rIkѪȂԯX0m R͉xzZSeMUYs*sU^*ss2||POWn0R50#ba#Vla堍8k.*$n*4tp$\岞7ѰaZZFՔ x< &Ȇ_YBK،% E$ے:)-*Jc$\Y&S+lnG"^w b2*X[w@AP޲QJNɿ6R,jߧ Ci3IS5|5ܭ`;r;1P(v[.֭ˮXkե o>~OP玸wPJ>~|Oq0eZSn1 $f -H Llݺx@ A!5 H[Bmm,,[pᔌ-}ʟ N^czYvVJ @{(XC1]#4v8K=p%ٔ;eFJUH@U1f圣 f%+0+,M%t(,qH&aFܫjcN˚]~k1 dg\b5V9$㭽.KCs!RC6>iyj`,bk8Zn`BkKFI(g=ШHRgdCQO+b%Y*nf)Ypq&Zeꂛ6༙\tǨʑ]+0vCZcZ%ǭb_ (e PiϦ-iWS 1]i-Yc;k+}(smCQ,30maB݉&\tWetEm nWRF=*8pfF;#z~[9"7+D!+5ֶ)XS^pn,O˯"\_|3,9J"Z@X陘.[ze2mm%ثЖ. |d)a_gyCz희n^xL+'S3sF(=g$dqˬ8DQiSՌqlr0rT\o"ѐz dacUn7;i03!m4b$ Em9UDsZcHm ILQ5D䌢>' ON}ɄKW9Y)X,eAxJd>" gG'98bM\ [$d-xKOkMY3#Ҫf,SZieN[n,ղs&I@Q*FqǬ`١bi+Ps ~]U <0-̬`*B w/&7ЍǓ*v9)R7c+W2(8kG5[9q(kfx_s`x`WRVɵ%'نY>B :j]KX؝yh=Tر*a,OlsT;4/~;|tN#+*H? XΩ: &/M08sw'!;Hܴ)Hw_7M-쀣!~mNz|*%8=tUIѼ L7HEL46(փ"Lgboײ GDGzp-. k0SD!{|-_Kq='p1i|2^fyɂ>O]K躥>ڝ/MX߉,^(D'QꈢvM"h mcONOl| 1Fɯ 78EYv5/ˀPT#!%yҒB3ᄈ,KIT9$tYjx̡(yrd zjΚߒ(%!GeJ$ UIL^ifV4n|sڧ-ddi¨h8{:l*T. nܷك)]9~fj<6(mWzC⥥F+k le(ap }5dx5,EV؞/Bd>867o0^8r'y[z:`W +`Άü޻|K[nb"/<Ϯ~=jW Tl[M*z_EC\61>f,!8! x{9,w)g8uu61_d6Zc$Ecr^iV7wn.fl"үg<1>!1zȹÓV >.iZ bQ&Z)9,}Ʊ`i(Q[2=rO{ ^7>g#<|FC.y &-R!ui=}M3^G4 Aq$킝航4bs%xZq/ՖPX$гK$Qd܉{Nٖx&/~D.0~@"M /bis\ѐzzU([v/KOI)[,eIH- WSiN>o9\J CZq *ci9g'lxyRx!*dGV3jJRB¶e- 8jMN뮗]2(U3|wF}'785uHլq=/ZIC:M+ ֡f)Ծ;Y+=M;08~qWAHKi˚rz֍Z~yo,9]3d#"9wxeg2Y@.LWOWPwg|=/[O\p+.y Mc)M޿!xYXtP׌Z JqI*3TBkl^W~ʘG縻w{?ęӧM[JzaY![wţKrF,nt AY j5/ImKg+|k*5y0X,gބwe hYpo鳙&uEŊsJiE*=> IO2`Y+z¢< IB z>k~Ml\W'~Y=0o0&AX˺]jd,ɌAmQ֚Yr @BQV^d-ӰWI$✩+ڄ;*gCKmv(LVƃUrUF5#КfS3.\,Ye@R;<}6G:1iF궎I')[goc! [=W/3Y4MD8 M] T8 E$qb}kx̧r }\pxt}K?bA|-iy˜{狜'pp|6q v&wG^|΁ ǂ>:,@,]%FېD@"cX2L5}a q)㜵X[y'K(_ .q?n5/,+Nja4|i_ǿN[x2A]9wֹ $EͼDMbj|<,["%yȟ}fE:4`vi~?c=8.Zv2 !o~YC J!8䇟C|i lxLXa$)+C*[9tn l)zk>;zfV! 5כ? TKO̢ Zq1qi=b)T@3dixQsPR0o%1%,>ih>2Їf Fa;ye ߈g;\k-6p6["F`Q;Ǡӛ.!K= 4?ś7˛N|:rQQtʽk= 7|N^] q\. _zu~׸H,NÇ_aX|]$ӃCŹt$#8ᐬ\!@છC}:%GXA!l \uȀ[h@DiAYB: V+a8~U,>g}ά~ ljgO| =q&[b}KI34u蓎s vdAMHm<TTRl TdLۀM&.ިO 쌡/-I.+vsÙ@ba٢Yj"d;9._^sXIY$1(+qPWL(N˒; '4rǜs>8rF4~ T@zÔADbk#r5[JP=r6ikEiC^7 TI[L% mrX)IJ64J0#Vm&'VCQn'}8à5xŢq#8MAfy^u=z8 5@o^'BoQZ{G1ve0N2D;k0u{ 0X$\ Oܕ~~Υ# Ro=g?p9GynY :~P";(]d+Ю *{{# Bzl؂AMlcNQV+@2R 33 {?s\YO}xqJ ^riazs_?ϿMNm:ӦV@QY|2 59i3b[c#1jV-=g$xf/ ~ګd!3PB(h(jwek;ǵ3],KC?iA<^'eAiNc{PsT®qNM`3cra.c4ME)9xql 4dYxG  ܬ|8il7\4mҗx68^e8ZƆZn ^fۂ{!XEPT?f*,utQv{k Noy$6\a=w-;?`ȍ+ =g prMk'E x] a]́&:h#ÍX;BPYBiBouhPNa6s0/s {eWaZk6$)sbak#>a5$^f9Y2(` h mNTOnBm̓WdF.HСǼ2 '',)z]Ϧ^2HJ =ߢb5[\HeUl1P#Oe9VߝCH37:-(Yhau y9 y%Ђ?!vIx=&w߳*ZuIduU #l-PBq'!yl{p0çF^֮ zēSjoׄl0=׮p vK^4 HTƛuLjX9qü:A~bYXZJҬ8p|Fz0 6p*k]9`9TBCe|V}~x .=+˫LbhSXs6&g>_\n% PĤmMxLj!,2jÈ'|Z\3-eS֊؂@)]͵Uέ2[4A!*la 'XXChy6pYmNe q[9YaԭRPq8e Y$Q,[Ɔ۪" Vͮ8{K~Fd̵$ГfW&U(\N,/[ߟjyJ;"ziW3+ZHW .䭣Z 4iB8Qt tƔa 7O7 MQc#̽X߱k?X!<& ` rNơl;&G&b>7UvFPp(13Xpp Ү @ <;epwwƈWc;ңGbɫQgÆWCrosP,1ŶGЎBcbCj OB)0NCCW 8LsqD_#_Ds[뒸|[?{_S|3W1CK3`F2 Sz}%)`,j,3;k&CT 籞b8,EbT5b> 4+A*Y^#&lKE0\)IXae.cuId:Q[w,I+m8*08YѴ@cXS#2-b)bʙ+<ҒA ,AH0Pq,#ekH9 S590BlwOPþkAbCzdUI*l&0;H#{YϜpNuuXpg$pw@_"wIh9e`@OCwֵ˽58=s{ jXyt0oO2Hd7+;PNkc)Ǩm.Ξ%B"$#ʲ[TH6 bK/ 4A~ޯShI>Q|o} zgYNy y-|gǿ- >xŷkakDZF!#FkN%̇RYdSzn-qAbʒ"&w<-˝,Đ *m<,S s|rqkv'  &/ 4fe@O5AHg5[^]+MF,)c_Xj/@48%;e2`@Qg[Kk9׳m>[ob9+hV\{[9Z" `Е<빓-I@Ky4M 0Wx@NJMwk;}{- nmh׽t̲y_w}#DL*̃;d޿޿i΁2  춰܃ ;RWuֱt(p CQ &ejʇ&k<ڀ=6M>yC _U5+MT&CkNe!CR9Xu0vb)|靼_fg}e#~C,v[vgMvq33+x~zsZz[zc Fs(%9xHBۖw|8YM6Ť3kcdܬpAZux6o 7 h%lƉkkkK*C BX(kwJmBК뀭/ّD?n@xы SYgMx'^}CN\ [KVCqm n͜iM<2V[rv܂n`;G?뛼Yo ?*M'apenk: t$Y=jc+ˊ)hpp>=RzY,m-<; F6<;=WhWd*?DږRKRah T0Ӷ =u5@Cv5F MWY-iWrODV4_YBd{<-mM/!* ? (ׂg(d(X"Hْ]qkbWZn v퐝4$7ʱB2DPTK(be)„)PFc\2Ns5oq2uA'ȕv r~8L\%s+<쇮Ұ!<2vm.`%{H>TI|~^:wHȃF9pqmu!+~2s%۶>ƭN܀8tBhZ9|xR8>f 4(Z5%n k-lVUZ2Ɓf7|Y4.%0˿ۻoGe3vC QK- |i466ήF0+&%[ #Yi6K)-ßb='mp8y;x' '|Ŀ˩P3=kžï 7'~G9sOl]F¶x§E{I/d:WbI_zmZG̴ǚuEܚ YZ12)etIx<_D<ba%B6{c ҒX 6!0P4 Ke"DNl5 /BRI)1Q6jQ,[ 5K7y7QVVMR 'Mb88t@dJs-l\Rb(K0- mwⵝeW0 l1#eK53]$MG<}b4GofyHFkH,wVz<7_㑣'׭{2tTA҃F!jrڕ1YbvJĠ׃{n<*<`{ˋ'h9tkbZҽz5[+t^21{ w!9Щ Fbgp^NUCK<Չ|3fR| / FˬY{@|ɧxx,|?bNhMjyʏVkE`5B 8+F3{''iZl0WF=5dF\qI3G&1Uɐp}ȱ p!hG jS؂ecd  CQ% nJ"׆P>jICIe!A֔-LQЋzҍȅ l+NMM$v&\_~F?ucJm- _V5Zqr\/+ •.z$,+W5,JTUs>Vc8،qhVJ;MϺ>?o` v/]Q4I0#ZzN|b骘w#[2t<ਖ਼w~6Zp0uQA<T}8l{vL5PϠ Aa<ĉ'94<\#瀬 4`Y.`rdҭs_袠?k.r'3\o g|۴-4rAW@?s嵿|9G˧[~ D&ȫLh"aY-.}V[r(Qxe޲_Y )xCFy#αEb2c}0`U'\4>US-H&򈞰H) o*I k 0dL@9Qj[VC!6Sc Ku9T$e֢[ٶT F|yd(5mQԀsZF|ஏcWst\ߝIJD'WAXYHI+ځ3@vraK$_z_zK~QІ1Kˆnyamv 8yCl}J8Ex YVF(ZLDd"{S8uрdKۇ893BѰ7wquP:oQ eis܃| `ZNeHg49IZ)aApXg KE{j#W*W|I^\?B]NAo{bc vA6v?G{Y]ai S%/)mnUBӰUI^{s1yC?X5s2sGdDrmrmr~Zj+|7 J? C[0ۜ% Kl]W ~H|j20bڪ =B$ V~Lu%2,')0a5tNwy+ҝiZ0L1tڏ(s܂v BxL[1h[^5{l}?\}c1(=3DQ(m/\:NJK}FU:{?, @F.%C %ئ%/r_G뾳pkbQ;2d+n57sTΜrq;%pc\D59“d&':!қOFO/DKik"rs+WۿIۓ2PDpn|@ͩ&{j~;<3Tgc66os=^89 /}NG.gzU4M+="Kk$UU1C"θWyP*mIlE)ȷ$ez C#cS-(Z[jrt6Pנ/%T-KSi@h N+X0!X+$o{>,f0LPQ-jY^@]6xPɔ@*M7ޟ+t~s \|_y.#isAֶl܂JBut}v}2Jp3B|-7'BWmSDw$cCk0=NBWu r54 WvIu%IP [K~SNaY*%4ec䪮p7b-ZN|3 ,]>p P; b ;L (go޽!qsw|q"Wi)OUmr!֬2|dcn{؛Y^ys;g9ܭ4?W'' wڿB-fׯu/Oj[׏ <{\pB}9Fqф2x֣#_2-̒56sp7mg9"i}|6Y1=JFz coK $tm㱩KAĶcmVĞXXba Hk Ca|I>i|Ao)Yu⬏0M$ 3 O e lK0c W!0o(ZN~GQq% k \T'0w$: pfw!nQ}WZ` S|Lܴl\cB $Z^TB:C];Ʀ{m}S崾Pypx -~+XW1L@Pܠ!"zD˄V4T~ Kll>>xc|+ۿٟf;3$2BcZ6̓m ]Qј otiɷ$ &&5[j16y+Fr!EެaoH#̲A/DGl4})(mтu7BːW3[^DlE(Ӧe+` B 0#($$*GK`D-!Mwv>~'$b邲(܉wߡa~ a >uyveEV ާno;iKPx.XKvȯ_S 'y>W~+/<9Khg`P.Z* Kʆ*qGoNl|&'B&s kZT'4-|Y).cgKN9aÊLP @hKj JZgyƶXmiexk)32#@XK* + f.# +h[KrN;C5JcZZ B)}uz;#bU8>w*,JcBw6E+yI/E*Hjرa'~9>u-J]9@Z`@p )݉,n}BS];^ s]4•#Lc?` EÇ䂼Q.Y, ɰ:{JgNqHw{=~}6̪%LOn??gJ~%jۅ\@^`zu TLBͺYL{ha]AG0u?J>џc#<z^ m1ї6ٷ< 8o0 6x?޷1x`t?CНQw*^r]J,xV:_wZ+F[;Y>93_.ߟue`,w?ֻ{>5$qj{ ;0i j[0~c(;Mw O~ ֽcPXLwd.i?ت[^u=|"1{?:z藓/u%:݁3q #N*L- U MĶ<cZVRs,\Mo{kGO֒Wǟ``mw|lV!^z׹gz\m^ڿ לp77/~U-º%P5J)aG|teiC EQ&jZ>F j^jR+44o$ i R#"VRPwS ڂR4ZWK cH:O!=MAjwf1$&qj}.Ka=)zɔ"{CTM>m7||\:O@O-aʘ xꬿ\bLA zP1 #`S$!fШeu PA4~ d0 :t.9($T*o$X/!: NChMIzh$`$AK !(4]pjI| UQNG =T!x0+Pwh:zAGݕ}ya0 *ʓ_\a %XUܗf\kSWk!cR3 x ۫|1sOǨ %aBLxl=q+: Ao.R5rA&Y#-:G6>+1}. 7)^Ϡ:nchyLkhW ҃5_g@|5 H1.b>iܑl4 b58A0,v,X&yIqJ肢qp`|@/sغ"~kmwoCк@5dJw*N%&J.HVD.T<w{q6P* C !B$d ;G|IdC!*g4Ri1tĉ$DEno}/!@$2* Tl: =TW) poZU!$V߫ki2&N 'j&(W♎Z_n@2gwwxo}zX{IH ׅ{N"hE&=hB_NtW=դ qbXu[?6cw"HV}K?'A.|ѱ8HgВAק,qfAukTx~WQą1? _"'X|⾇I^{@,Q]#;nþq nbDhPޣ;[?t㍧>O|ېP&(dQ.$ ꂠrc5\kRch1.~3 H`, ̝ Pc!" N~}\ ͜ਟ2H@XOԶe?@B &DsD ^ߜwB@>qCzUnR)qpIB[“ZFÐ>x*AYR}nvl2>?6JCN^K~H/!땑iE"TƏXFSoNM~ߙǐL RG[ɴ`=aZ4]˪,N$v^vq+bAj8vW`IiLo5]K{X)ֺ; sj'gߡ_^?Ƙ E#6}7!]PtcxQ\KRimBغѧ(5 !7_姞șkq:b/VhZz-PJ tAR_u1Ai`G,M.ukEZ]lz!Pt/C8 d6~AJ@;]!./.&w*ԝƫdE(K(].I`1=(HEtnQ=8 ߚ)aܽjj<癸_{'minAs2A^Ӑ$BdbiƟw1Eq2E%5<<[khG:{O0[${Ն>$j:T)6QTyq߿1dde|qg0t0q R#ݚ? 2Z)4r3h$m)F+9 ?*kG͛'k Ո'߇t)6=}lU ܺrwKG>s񭛄cŐY^7:4hbUFm=+0A#%UgKE' dx$IO PxGu&Nf^u `S P~#u&HRd\0h+/ Bki/+Dj Mw:gBįUđ$(@xCxM'pUM*\@4&n6$4Zfe4(i!It*%I5i_UBІT  Yy/'IrQDߩPI4 HA]^T=G::}"l.fUP:TYDm i~w14%60w) EaAӢ/θ{_IN0 "H-=I$! 2nË 8T<8|f]S4e#879t=p< .N'2wi.q}QC $=O݇"7CVX@">P!J%*Yu!8ˑgDЪ}(#fa'P߿tWnGxN8Ɯ`9sr箣^ ҟzɠd<~k߆r BqyؙYz dfy_xpwkcWB AGZe[m2K"B`JZT  k !ҙP,DKT,uG1]#輢QVhb$dY'KBp8TF!bH Ȁ9Až̨sI@I!+3jBvкn譩s u_z0*mMOe)R$"&րI!E$f2ȓ5b! '"P%_)b"!"=P R(Ŭ@,znAxTz\ HuDg|첁eí6E\zi][8Cz`?ȣ84\40p0ي k ?",TYJXq๿8t4Bs{qOܼG, Co_"N ٘~utRT>F>Ws~Y @Rz %`34p2}F2_&mQ(i TT9F*x%14If]u.16Z".zܪ;alM@9V$~ůq'|-?-}m2h4f\׽/t>[0g^Gu~z Aԅ\\-iw'0\G^ .CPwi-T75h[n:>w:ߺw{3HKDF ^U4PHX!Tػӂ ]7-O~ p`V^ *'l.-Պђw@44禼ڏ1W!FyBӲ'o0KK*H㨪3tMl2 ]ʇɀיFHP;昿wӋ\% Dtйt$c 4ĶIb'%ZRW zFC%R**@-2RoY*hlhG|lDlX/qR\DB.E{m'8.7^)B)S'Hr䐬*dk4!40DZ_M#%7"`&~IW1 QwNŇ!^.G]'ܽ;`MTubU^kд}1J\qh`YQԶ+G#(7X{o#S9Y>K4{[{}L R3'AU=-M<2pU\P-5Z AK$Cozf%ILVZoɃ$KEDPKfTa\&"#Uʇٌ"5a"%^:ࢯ$/"nI݊@34[* ЄH^҈eNR~45&Q,wgzjbh:^\t&FX :ȥ:LYǎcm u&XFYh!3?|OnV+d0aQt| |;a[̄. hLȟ'g + MMX !Ҝk=bFoh]=/w(ע~@j>rY^Aq(w:w|*oWcXxS~,-ԟC,fsEmZ$F3C>@65N'6\)G\8uϽWw}#PT NP@,fz& V+LIVq"J3P%jyb:K &} -HUfClNjicj۷~Ֆv+ .aߟ-ap v] 1:hǶ+tPyl1JS+4 Qr *t,ǘϾ/,_{_x˴,˔ sZ~UqSϱzO{ՌKpg;e@R*|n賧9Gx(dmwf}+)GfdZ-_y;~U^o,E9M [NԿWP%,Ԙݳۘ7^00+jlǚ2Ҥ:c"mG #ȥfWH ! ,G!5B:;*,UI|z }KK;Pb.֘,7i\н1!0<2}KA1"/S5i:( 2ӡMβ_i$#OptJCc8 ?w *v!"UMdw/28RhwYmko797?b !*@BZ QU}h:tU .aTNIW틸U.pX[.mLJo^18 mza6v-nªMY7a:0)fMLK`QwZ Z )o CayTx-㴨 ^EE6ʻmrg)XS{re+WFU˟|;ƙb@Լ]OlyMڶx=d(s>̟)є&heLxVDʆXP,!%8$:QA\="J˒#H͇*~1G] 7$:),">`: ` )|MhUA*O@/(cbU;}ֿaJE[UC3*ZU?>][ZJN,qep2K:9FjjX.R" Z)|pֻo{.q!ږs#(Gm/h-F%N8LJ^.D})G趍HKD&V_z?3k` BBpE4NC?'#Z}v<ڇ09T3kĞbhUSZMF6 粎oLy79~>u@ |rMnvy5<2lSkmqtS߹tpl3R#LK]#r1kĒ*Oyley,0[P7瞠'o~i`eRpWW^ޡF޳/S!DG4"_#mM&5Iܔ6$T`7xgHNRC"Q(Ts`=B kXʔ̶(Hd/V aҒ0|RDh5hFNcЉ dc4A1+BB ~x( ս AFAYEʯw sQuTZYG$b+iR6ˡn:cY6%d" ְjY{!>!A&(my9&+!]6BLs|'i.^.q*݃~Q8:qhn3^.ƣ;q~Ğ m(­;zW{7 ܾC-azkjFq2s!9$l/y_(k 3M.O^*w]y[WF)Ƕ ^ٖ#!%au!x({\ UbPu7wewC^ލ&KMw8&G#ۆj8ez W2Rz]Iss8I~_,$in9Uiwsx%2)"t qG'A kیizW>?dcP9$LN# ~]x=쫿Xx:q|!LWMl2Rk0G jd!;n]SpMBwͰE&ߞ%VfRxClYܬo~᧞G> 傯k"C W?'&HW_f_\NT$~^7&;]9>d$޳+[0\2fI4"X* lȆI1xL%(YHQ11#M0њ.>e%#eGb&GB(ň\x:ph<lj!q!pG iA"$ b.5 @$yhI22^Ǧ&IJc'kiR!J!1R3ص5dUM6ޣ}bMG{Xϲ(l߽TI7 {&[]GJd m2U,gӄ#V0؀ȹ_IrUN?:rU~ Pp3P#.B=B,nAWV} ]YġC]ܸ hy(H&~[p)xi69з(aqZLj4 p;)o׏q3[]R]Mra j-?2͝c^S2 :ѼYP&>}6U u[9 Ii0p*8S&5ְ!=7""6Gx  ϾHSLsJ ;C*%V.6 uJR !q2#=Nu; IQUkHa$4[Bkh"guY~t-؋5-g$bk j>K2kH5;!,p(2霃Sx}={JGtI7Q PE #DŽ6bg`}:llhY)&lQ24kF߹뚫=q[TZQ,glzbMVγ=x;:$u :ׁ%45 2o[G;KB>r7uv467!Ds V) L)7M~~=b| ҳP `ebWz q 1C]3d'OOS7Ԝy.9TN6g_JnUͰ3ʳ3?gx\۳a+A05uhA U? r̃_1-Ird>|"O|U}Gj ˁ#Ϊ\MIC@fx|3|M/G`v,Y9.Hc!W\JEFԪض!9vLu'97TBb-Bka u>+f>P F` )[Lė؇hQ WV& DyBB6h0O"5+OYe% 6:dӂeg^]u: QWS/9I!`,Ig2EUu啎!:i] H!yB1п@<)؁=xǤr:lQb{>G_G$.!bmOr|V*}w0FG,gyd֛/rܺ9O=̠YB@R` XfQ> <@!=GJ1rY#*eKwtho>Hzu#6n0L!ڲ.h 3.!-Bٔa9O G_*|i^O׬o9Z&Qr0?4fC>+oܟdd]:GzOyHz['cқ/6>qL2> cd,3gc?'<' UijR`hV, w#OrP6-hk)BVf,.x$㦡)R0pLH E%T=?w!$˔vPCJy&S w58 ૪i78;+}GZ"-k@iInZVy2!Tvc3O2u.l\| 3[0p;j\dF M@urJa ,$'LN8>b0?GoD)Y׀b ֛%֧[5naGnr 9~Y<_OdPpS:%,x9?fԼKNru]ro{<ΨyՃ<P N*x"R.ۘb%%A'(c"HE#Qw-g O"mksr=ZΑi'B6 \-CQ{<75N?.7ӶՆ'$H-'QMHweS|9LβymX?M( oOW31dˈa w_Wc͏_T#ܿZlsp$P Esm l;&Fo[<> l83΋(1mG'Ѫg_;]^>P<= :-hHC }K:rŻ9IxjÏK׹Jt*_>WHk-go7\N8ãa#Ga;#a#, k:3 fG5kIF+R: Xp,$8XIltNI:KbZ6( ҌYX%55:Fs2!iFX 0& O$Yp16MK%5W!8! PDŽDw-(EЛVYZ !bsPA;J6Ղv8DڎG}q[v7[ tƫsז?북lk=_x'v]BZRC418]bǧQnߎv g%[ĨM,0.≮[1\MiŵՂ 6f6b7>[ w أTG`feaFܗx8ɧv8#._+soޟ*Us1p׀(d39^ Ec;w}}_}w M(WǞ`M n 9W9ʟ2M2!YU? IǫO9!9M`mR9JP MM rqZJv$Ȝa7)V̥ddIF]Lp ݊[6P`Pَr8bc `:mM!bZp1K#5$jUؖ?+)!&N %"~4l\U\p.TZ153%XHz[1l1 HM,Mr\G%9·ӛ8(cB"eUJ(1L ",*` $Ż%R%vI P#!XyH35ƻ<$e$# ]LRƦW `mf4:!5.DeB$_Ekqy^ՄAKŌ9auT:kc XֶP7,I6o5&\~|wy[|-L;_:> 1{7HM6X@2g,2SL\a&4yjŃoJgF^[AA#8~9kcHޠ 8HՂlm \f?wk4|SJUs&#w\->pcүk.~V6 d OKb_bBkBqK-9P"͜rKrƖ =|$I9c=Z>§n̏jyCz?vkkFJbB 兀ňv 'B1îHPr9PsJBT45 ɑ]˶NY؎QVųY `8 yݰ%Ju[,d:v +&xTú̄dD@6Ħem-R`,C)Y`,%VZ4f$iVhp 66# OzO_땭0d2=d HK|6ETe,)8!ɧ|Y(VKFmD oVOhe;(}%Z'S 0YB,N-ɀ0_Đt?̛~^{l@% ^n.o$cK/!V{jfX1}JGX.~Y\(ۗC71by #GgYԧTXCZFkM-2Y?UXtLrms,`(ͣط&jNdz7T:uJxM D]RX Z2u%R(!rF1\Qmi @JMVp!h\Y0p;lg9-Fp9DvC<{"btqVh!ɑq шChh;*bQj#{"0=IX41"p4}Dd9:!2.)m* hh/b\xl2L"vy-jD'nfiFk,n0^.cH>*ɢ~6tuŋ6n}4pOo^DSuw.5AKPؖycSF`njf5T!ȵ8sLo88 7X 0RA"|L <.QB2 pKhk)$\ļyd"P *)pΠtB Jktx) ΐ zb}\VX\Hw9g08 ne/ѥ[ R{{ynMg;B&kdaR:AW`맸u"Q@M'5#);AdfXC6UʚHg E~Hf1 Qt;dcRmg, kȽe$JC~4W§从WD 笱\ ̩>~̢7^g_:n6.ZmH4qqGJ5l,e[hp,4mV)G!pv;JJ"pǮ0֑:9ڠX,w eIy42 6Ko C1)[b`q %IΆI\I$2 %hB@ Ch┊g}:\#=_R/m"6 Fb4V|8iN'mi1m $,Γh uH:2x\R A6ђ\pT5GIA iM:Y5>` M; _gbbk(wëjA 08G`kGRRejkTu ;,E6.h"7ɂH 9brFd#QX+R*Æ9È3٘S$ K\R/ne6Dt-7~7xhj`~̿r5_˝gqb*OAmhSAIpT5bep+i΄Ex9lp%v_n wIHXW9ل|f5Q OYX]G;:xF2%Ӓ&y@yqcw:(*BQdP_Ʒ/P"U4^VEYξXJ, z_6c KbR2:˾PdwAB&±,$攌 UӬҌLF"P 5C4F'v3^CsWXt#DSG1G3Q\ێ;_R%81HCPۯPmȶH4 5bSԤjV-ԣkMI@9'(2FvČtCֺkݐ ?bNXh!t,>|(KDհMɆ*GSIv }!OQ a[mPfvww*W8#$F'- _٧E$ _);"|G xxܶ\MS0 zE)%$o|wtY߬(d4!% q:tcR+GńHJS%t QT`8 Zg⑜;@1J4R1S˄I)oi,@е8T~cSkڤD.Ҙ"P%MRĨ ]^E4t v1N?\-zci52oBcC+?|LϺp$sD5!7-nt+Ië:WFڟjyNkv՞dwդ(J) D$X2b$'A1H ɶ"Y"%ZdwPs)!$-`B~y=9MOA߆-h,\=va5}s>ZO)dōَI\-B)l4 |.GT7J[\q}J?8 tDϤWhr2 ݌ )vg7lG߾7_K<*zi=L %* 6H8/fYQADpqq蠜Eڈ?IN6fLl W"/Q>~:ëT_70~Sǿ&8_(?HpソşwCr6+حGNp~p͹x|ӏ"}w s4ƌ,por8Yrl_xþŻ GhBEyPʜ!J\ڵmǴ_k:(ҊI'!(4t_p}Y Ko7|wwNcp vM/%IOdD(GGs9;y(tńz(mH%NJKA-ҤK` (IHַDaTiNt&R >P̣z S4"\(fR,Idb`@KDBp@ EfU2Aٞ܏QbC>ޡ`8x"\5xBC[m@er:#1)CEh+!"&sydJ'!"A&9GB:KC&`&R8b8Bߤ=@ N`6$ZgӟU7<'sǏ,xoW=|$<Kৗ˱ PHF`CcD@6 9;|ug\U`_xL Lsgy[Ha?8^zP=u0)! e5.{p \Fˡ1c%S!iB=AӔ>ʱ JX EɴAxZJ 9Pp:HRW:I R!h@c(i"'2zRIsB[}0"$#htMr|#R!(5…j{ _QŻ谒utL+;&._^3n%n7zKg>Ql9f7I2qa[:EZ0} ɜж|L+' FNQF6P[*Ir|uNs5@^mO:ߡ*?KJ%-Qqv.429"Cr@!Ct\K.`8 TS 7 ІF6)(`*W?} +dJ1$Ae0Ixzn=~_: gxƪo9r6otG+Ni 7v4nq9Ӯ#%t"V)Y~$g$=[UvKCkvGD2O&5)3Dt޲Vg,A1 CC atʓh8RJ)fP(EJm^" $IF1 le(BjcҸ%S +(!*ht7@>NPW[Li1dj=2-/#|X`|J 4yY\C7a ל. JS}UiCi&(Ֆ_g(thRv-}zSںF٧ 5ESLgLw[ʬڎCp!2s)+%ѶL!6 Xcf!UCn(7a2Xk+9 k4aʼnBx˾\ ɁY%V29F<}TdR cOH!3>Ԉ0PHkrw >IWIJM?}i-k"J pYL 6c!͉ٷr}$fl:W04>nwIZT![vɮΰ:)qy+t AgvESb^6Hᇿƹ71biK6WLʖG'w__?S|hyI M^73Xc?K~_ůՓ)Nɔc b+!jR $%9%aL&EtD $ E)P ZۑOߵ|voM͍NJKgʴO#%h0Ya}d~Hҷl^<;AO^O ?W|5mC" _Or&B<@' Z|4x'"XlzXaWG bA8)Xu'?DT Ιئ)d]D-!IEĄHct->CYk9"I0R)c>#D;D1'F*C u$8δ&HҎA *rklv0_B ^]4ˮFԑx <ΖzO2D'_ҷ cX]ci'撰kuj6n2E^ӥ7*`[9!͈:!vgr&cgQ"߂\Ɍ׾fT)ksÏ?NPGX2٤sD=dg$$/Vqʟc|ѓ)|.Ƃg)=,% &!e`FT Q3`4Z3`Ɋ'/~ܲ33n~p_3y=r2Q =IVPxY=uK ט E||3巿pũMo{,x fyPsYo'G ^qX_l,)m){=s%H3ݚ=ZKz՚yYIE Om*%o:D2`%" tԁ1MNH}[ *2lf|jjFګs$2eB#e0pR$JQ2Q| qJ<2:FI|+ @z=.$?+wZAQdF[ӕ3ryq?f&!쟠No\;y0?@5.ay<*nr:;bX,s~pcVf'}xcMNF7KGhq s%roN<}!._궔zJ4>Bz/^<$s5ՙe>gvݎ%xW|"M3_짿'Nywc\yiZ Y4L\;&Ϟ:ĩgX\ܸIɰ{3셔iiXsHtZ^[ٔ?po_i1UL{.Î'į3|Yï>ˬ+7x7TS9g~L2"HcRAsE[θDSUb)%KsT =WZudҠ{ bW} Ecd&G̜=i#)gIx@G#$}tpCqyKFpd|FD:%6;; HE2'H/{d@Tm[x)IL**˜%b຅{]wg Ri6~Op׫%!+Gz$;@^1o 썻LO_]3aVO9J<ػxDC)m&y@y?pPW e$pip! =ߠu&lx%>]$db7?‹f{|j}gGqN9{,尌4e#O`HB:~ ZUܺw?/.g7yWԟF> R@m'Sworw(&bzax`o]A+Y4vK j`X1JGc"%xݞ _\c)h2 75Iw_79i9|<᲻FAxW**qDfաDU`HJK:o׬t`QpyN4IΞw\1HBK=#ɉa9C4kIJw.#! #xDC:t:Ays{PW!wkCsd 9]L yضc$;ASBPRJC-z,2^~BbYvCx~'y *䀩=cUw=fln}=nS;![<$xmZBqNdb=//?rquE7/?!>hG*ˁ;Fk O!=ҭ\&W~M~?ocZ=OcW_27aJI{G?*՗L|}Zaz߸~yѱjR?eqyt-IyGleSlCКq q!rf,dvqwQ"d{p)h# V9D`d4TQRx(BÁV|6+ {r,:WɄkIB~~:v!PTXz=Ācʠ B)62%Qt :->5f=&RᒜS\FsT"|@Pq p:#^<'XnNA&ĦFk;c=<|e;0=bGUTLN?&_]f#]>#'ΐ/?;?_o8#c?(֖h !<:I!]e4:aoi( j)yG&Q ;BmqR҇ #d*G}{"C>D-46"BrAB "F  ُ~$ orLca- 6.P`'zH3= +BʀE Z9leqRh[!8 5:#sT 0y7+sI]d:{$f%2Cͨ kM8MӍ<1ipBU#f.+G^|1ǿE#LfpvU12`&gsž~67܆,@ +xo]bzZgP= egUѼ>9;*[{o|}Yeo2/-ӄUwbB 4=_͌{t'!};i90}:a9M~߿C%On`zO?*7czmV^#>j?z)/z#Ӱ؛!])Z[1s욊[:ls R'B%1<İ:|?F:x,㨘 "+T$e;@2LaK|{3$*4N(ZrԬfF CE'rfX60x)>PjM,Fr/FYF!\)_jy] E%ĈORrMq1P$I!d tB#")!`&o YJ]Vju&Ȯy!7[R\Q~]G_6W5Sop|G @Z@7Y<IÚ^|a3s}:~)IcNOAO0n@]-%" ĠY90 E-hv\ӽkwϘr禘6ΘGjIt )#w>BE>H+֢#nj.nFŧXXKȹ 70FN<)x($OT̅SєsތSp2'6u;S`c4^Sds&lBbe(Xؖ,|GL1"BD* Y9E-2uk.ՌE%)a\dpEt)tmZbED0b< ozFx@G&EO($"-2зm!-G8 DS1/? slQ0W -kUg}+ێ#X]N͊*B@3p'veN$KftX]BJ chPOGSL-Ubkܝ"yۓW'W[753_~ w@<%i~h'L) vok,w|ѯYo1K)?yU]&Y:g uS#@+Tp@HӔONP}4֣\&$k(hRc#4'j?UhrO\CSCV`tP03ćߤ>M63-as|beflT˗yݭyCnTk͚{_7x{%lcP 7:%[Qh_-ٯrU>"&ļq!_6g6x@njǮ͑Carf1TszNR{o놽ś{;-_4u[e ;g D TҢGsXtц6-̏d k; >v)Ʊ2= B*OxHNzdN(cT)&2o[9{jhR)Oڊ&C]p{k !7Q. $%K.K }h^9:q%W&m))zFhBM|Q ONR7'bF|!<8J})1FvβKpcVtʧRSX1 Sytt*:J2&xܐ@Jfuk2C EPzY FN, m(܀?Xc֟[ހa~HvdDmS=ćߠ6)vu w(Kl=bq2Ot͚=8 4o|89Q7c`й\Ϙ]^gqvzzlަJqq>'n)iMma ާ#2vCɂg ]IwQ,_r[W ,ٓ/)ĎJ\|JxfV*r>{LEr!(Ҟ_d VgaMQM|W}fB3+AJLhA; \$\T955YHI4&5\{ BOOGmr3*κU'H~71As#-7W _0Jm\%Sxϕ)(D­t´ІD̓$x0(CSBH "R)1 ,!bBe2Eu;J %89ؓ)A(.権0HUew$#. ~GBE%+h^nTd>oq*(AFGELBA4q\."6PWD>f ?b6CK>j3!v-wfy >3S h[vf=xqel_c6) G_@=.}ؼ@]}_7G;ns.ՐAS&fŰ!>AԾ@xs. }AoIKD+q*lOXsb?\DHCà;+U %r24(GKH04lS{d"/4*:` i>^SDd%BNdȑ>$Dߣ @݌YDpq;bF:8z3 XRb2 !;ńutM; i-3k\n; >.nGW1@,K 9.^_}ƞ;ewB, & Ax^?W)F QL t뒮/A D ' c)p ҉p|M1mS0EQFn#l1W3BYNRظ$,(1"," D1,=2D:߳Qr"Svvz=L0r̎{߮Y)H|\:GaPKϴ|sUH3Sↆ#!cy ,0DVtʭͫzBƍf > l7%udp$;RۣڏHd|!FÄtERH8v cD!"F2#z$u$ *XQy"e)Z)s{$ ;S>)iآ1E]؃E b6!n/iOޠ^1ø1-lO`qfGaw+ *Q0v I6Hѩ%YCHsbf~lǵds|٩3Rw1nUwC&ɂ#m:q(2ipΣE&9C&(hYM[B2r@; )0`I"DZ -Djc -҆%W&PHE%E9d *t"LĜ}ct  Z*< SqO.P8ɖ&w<Ñ޳Ւ<]:F{d  ;LI*g:^R`Z$e3ν 4J&T糨TLcŻ!*R]U%SG-~'a Jl? \ZiT0-+.GnQ$X0H`><e :aωe`G zH,h0:c'QtD:1XAk6ce*ls ĂbM./[r5e'!Ҍybm:3tBVwzG7'"Sס -k8@t5Zd O Î>)Ȇ-JY{O/=*Jf:DcԹFef-h}1WQtD]a+L݇bSpxS\~5eP4Z{'[dZ?E+n/pf9fn3|KS8x翊'䯣%W.r'l$yIBroL܍<\@-JK\qZ^vJfUS5*t~A=# M"DP")@b۞ (PH5P tġCTGTbfؙ/`f RذRBI:1ezPYJ T5t j{ސJED ,é *RE1I'خHMQ9@ nBN t hhAY:>h21NW(Grn+KEMyniIX qޔ1Ms.\>]چr:a"A&ƚFB$ZX:X@Ra@C'EAzГ)A\~0>QBT@e'ǎ >dlWd0P.F)ͷ/?÷a4q:'7&p ?;/>7wMc aDV l2gSI :Hx7@Naw t ]3ZuH5qq{4= -7V/76abLK)1MrH+ oC6=FՈo `T IsG8& _U*MuS7## <(t@˄B3%ǣ)~qJ;O׆fDӲ3g촣N["i\?"d` rp! %}*҆^Kl>&m&)ePL"L28Ը@a CQ`0Lc Ux))y T~@%9^$̆:jrxLX$v\:aJ)yD"<(bD73NҡL .l mpI#5QJ ["B($=M&c,AJ>p*^H&q. Axfik46*lUF٬HdBqM"jH nNt#5VΠnpy[a1AO c1^~wbϓ]>ofⷴpm!!z)QI @4ӱcٜp |D!dӂ8L`~QrXl51CsbzOHjv$2 RLZ0- ꐪSy'$( RE!S: HE z $ P_̯_D:L$`$#l,JzNQE8aERcUlȂYjGTf/jB&^3H2>L).˰]\LŁx}Kh Cx4ɘMԤ"ps`s TH8s *xXhG KS"#8c-(MziQ1& 2;*EfX(E +3܎!ɹ,0^q ϣ"O5w 0SG:E z.cb~QFxxq4 a2 h X#ұ;6CY) _o324:ZAx(on z0&J ^6=v}LX}4:!} * }$""} U" H/HOm.q*3!HZAIvlRE4c|r @₤4M4* `d@%1Ȉ $PH0#RyBlÖ˰\XDO CQ `,9U@A8jW#Lj(H9Tl E7[GF`wȨZZruB(ÕYs: R\XϾJj-yM%Ǫo)QPۚT)z-N`U]WӛbD1[>l_A}9v3i ÊKIpZKv&?JGo[ " ˼eHJ怡 hA)icIT$?xUAffo ]cmH@\uH[Г(U&\+ gB'AP )59()F)P19rdK'D$Ǽݥӊ $8m3EtX5 0Șt&)e,(cr.]G,(Pl>zR=CII]N9vuW1ڰfh4O\Os\nLH n1R~/lϠJk%a`KB/HKRiy^(yeσ,!ҫ-d2si={Ud@Q?+*fQ7Ru6c˞hbJP_A vy"P%QKK9LcMH$0;vg6zǂӍ#(#${ Sby0&W#)(A dQ.1/5LS凄-|O_G7 n.=Ss<Dfr,昲${o ]; tґW׸vEL{S[CCOj{ :2H Ǔ& C~}3Kd]2<笈t:rh.F˝8E ek)pXZBkۈ`ʎ")e`kvgʄJގ{2%ƞ;.}y1&k12sc".^&vÎ1S*@pzB= qRAЃJeGJ=!IjDJgnEsi ; qB ZVeȡAjg"! zˁl ΃b"s]myF!m@}Ķ#.F# ;.: l I!Sr@8B?rU !7> ?ގT!wψtBlkֈlj:@o^B'7@*K $iv1)Sbs}3*u/O.}[U>&[do-~Dd{I;nRl0h)gc2(B[MƂ [&Q'!A dc& w)  4{Ȁ¡c@vIwb,rct-lb@DMjƹ!0sLx\ .|K#=*Q=8q^SUG[ 5'hC;X% 9D^r )hmC)SQBsXa`)i 0v1KJTt2g,Ip|1c";q=sH%9!B(\##BDRSɂ&@: ]"s~dks*6 slJ 2!NnQ|oTݕGz| J(Gqy%"!"BZ^'\>!Ch8%1GB܃d Z`{ evC]3T7hLtNA?A|\j :Z=æ!;~'>^zL80eVYsl`!*9L۱9|F7ŔXbBbuPf +{b$gdwb#05,) "%)j`w}3 L Ò]M\M2  mG F&LՂBjD z6aUܲ-I64{Qb$31@(bC9@h:";"GH+Qב>0tL-N^qsWS)`0B!IH v` 2*fRS P#AJQXDdƕhI^ nஊcdX t( CAџ vfOH4pu.͚8&G Zol^Rp;ZKtkD!@0A -GOdd/Y;JcL@j {Zqk35l:b`?lL=lz2>D?tJˏXR60+KX&6)$U."2I- QN"W@ M0 [hO;<'xO)!10yb#bE4[mlk$ C6fS"aJpA_CHӘm[2d3 )s@(7 D(k ?KH!ZbͫK(1.i8bذDdR [D 8b_Nm9PKJm {zc=VNXĈL$ǒbD0S 4pz¡ 8YJe=蘅PHE"! JƞV Q2~?ʺ,U"g^PJ TsvjCT9L[lā/o A圅 Sd{7m̰!k:p ymHSO]OrAp2qL&Tt>gPnE+!]B3H'/!LʊEf7ˎ1;[(ΩEm3M(oQewaCTM/9GЯ bX҈ Y"rCIڗ,oҥo "-k s!}bO_ E` 9͑1% |9vm1v-!\'KP8H$XD 8>؂B !](Jkq"iȢ u,:^RgJ2~@UCVD1CLJ- H13YXd#HˊlO%z$B=Uh\(8@k"%KjlHbO3"De"R8;riFߦ$HEr⟘t s:﹥A'sIE>ro#L\(?O% ?C٭z>ޫһ-tD7qȡqj\4trAxZ ^?hBG|&sOH(n@sFl/8d9WuTEN:t4 %̏uЏ(hivgg[&v\VKls q(8kPL?Ϧ9$~ܞSMB;0\A`z(3L֕@-ݴo*xLhe]> !!BDKDxE9ϐӔЎ[5!#h5 n'.@gaB'Bѱg &6ٓp9zg7s攨@#C^"Ba7D %XL}F)dCĈ8TaME!+ v!IcT*@ I:S)A'DADr[Yp "EFO ŕRp RR)Bx;*PZ*Ay? @$PRUm(|;b6=jXr EL2fMw.;n#WN./cl&dEA1/]lm^%A&M-"Yu(J*2$>аDOgasC\(W #+?#2kw 7߲>̵ݎ;3B 嗰?i݊!8 ɗn77 JmB (8"VZ [VPؖ?Z`{ nM5C 5 J@lnsN.qz[y~ g_B瑰p@%ǯ+]M>͗85eAo%׺B4o4,XPipT@"U񶠞[DžFbuDe)lkK8A}C]GytluЋ#? P.| ı74T($g҈Gp};A18̖%'Wi[AUG%~ aUz9ozGQGh7I wo`QpB桤e'<=}c ;*8b_@~=d04y5;xX(@6l,+_EEu}<=oaw[XhWBȊ-^x֤˥=lਅA΀<DzQ:].PD5eQظa db|b Z!Ԉ h;I񐽀n=?T6o/Ѻi`l c)n]KJX<78>J2-.Nv-E͎3.i6xmGESPᒒ8cOģ2YG[4p9 @8{4ݓ ) x2RJ@\|ثRH6!'wtpzǃ=UXC`075oPJCN_ Oܢ>?)FS2t]hGӧ~7C?O7ZAlijN?=Y?ɧ<.LvaQӡXz|7a -_bc;m8ԛ8ᤖ!Y=±c0's(X0&=%dԓ cSI]?՟èM '!LELd_9:ϒNz+'z/2݁'HbjNi%GuHR$o;5%8?+n^Θ/-Of}Ig7C |SdV؈IX;L'¤A a<^g a9 XK]q75t$"$޸9-NZj&UWLEu SO/TPSpn&z:.jbP}jjRpx1tg 1a#+-󍩩v|s!vpq"$9"d` ėm z:}2T|dj!SsTߓ\ĈiI='VpN/gIa|fW׿ӟYԵar32SUL10L 00 0 0L 00 0 0L 00 0 0L 00 0 0L 00 0 0L 00 0 0L 00 0 0L 00 0 0>LaH lIENDB`mldemos-0.4.3/MLDemos/icons/ellipse.png000066400000000000000000000064621172143270300177440ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F]IDATxgQI*JX!Jk(PJ %S K(!3&џt)ր'ypI+`;vU}ňHPSѱ1C` 27 8qkD{o QmwmQV^b3cz>h-锺?/4m-o.Z^ g斥e!ppEQ[/7RkcEf/&"r}\:5ECi#:-s1d=nNx]ȶIjn{g3VJR@fYU9_ m-R3T x^)izDymf)귦ުrXE] Yn>sVəuWu۪ TmlKUp=euS ,lWp;+ Udo&Mښ{o&ﰎǀ8jN2:IENDB`mldemos-0.4.3/MLDemos/icons/erase.png000066400000000000000000000076501172143270300174060ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxKhTWs=wL&%hMj% ()҆UZB }e!. *-BZC\Tb0%UI:v2;3Nc3w;9"z:u5o0^-8p V]! L/gk8 `Zγ|-Zj!~B~\yVQ,} m$qܪ\8T(&WӂYǧ^S,;Rpx eV꽧\.wJ%Vpo3H! ]ŦвP(pڵK.Š$e`Ssbǀ_πJ:RV*@D9,[J%"\!wdp vs'\cK;8J7 n?\.J~ E .Jz^p+xj`!;V .f?OܢZeH(W>^`p)qY*Y(/y| ~vrft=jr0׏Yv8iz=O@{QXB4h"S6Ɛ)9sN—$9sNcssHwΩ,MZkq="xս{vLNNtttTkJ)e8ݜ|ؙ$I~vv)dIxJS,itRΟ?ѣG/J)=x7nz[Zk (l͞|~:tvv7n >XkQJ9ljGVk7Kj5?55\.$I9c\.W^c={144]__(Ai[kuV[k5)R !|ǵ(>* 碷sNZcho !lz凜ҧiZ\.+@MrDJ̛bkZ׵u\Eu)@H)]lZ2|e3`ӠDVDQde\F-B dsf@fǬ܀ij.f+2э -IENDB`mldemos-0.4.3/MLDemos/icons/eraser.png000066400000000000000000000121571172143270300175660ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F IDATx̘leǟwٝm*  \) W w΋ 6xфc$Ꙝ$Q"$^Ћ&+ W-]eﺥ,μs\٫M_o|y>i۶mB4D)Dp8u~._(/_i r''---$_\UUUN˲xGyD4]Sl;`sss$I=t0 2==MDQæHQQQ!dmfaʕՒ$u0 b6dYAZ7nܠ`p8Z4Me{bŊeYVU1g60ƀ1W_}EQg @@N&^xO˗?,It:&n&ܿ?~w]]¢E$ȵk(t w*xUU˹fY B!7 =J .@M)]9==oQ`EEq\tc&!1m,/..6<98Aʲl~P($4rΏ5H$Rrzri_GGGݖe@ [iߊm3-իWX(زe˄*Jio*mps˳o&DQɓ'I:gy֯_ϟ7:;;ŋ"0Xii)e9`Jlp΁1pܳg? s=###n۶ "mtppLOOs0@Sŋ U ]~1MH6l6 imۨ(JwށD""}}}9u֡zkk+pd`YdYE\.ʕ+dZ-=3 e݋7nܐ:Dx e0 J1ss&]/‰T|5M&P/..6{=0 ]WWGonn wvvȈR. <NNN3M1vJ}z].WO&y1PVVٻw/)}wdll  %K̶6$ιx Wf2qO("˲Hk< |TUUI$JAII a4-ؘsNWmn2ƜsED(**һ"y<`&,^زeMCDOXGDJJǚEr+b~Gl2#dZ[[1{Zd}{NQD( E׋Z___9"ƍ*?sLfҥiIBQSJG` -|! V ЫiF4I3ƀs~o>ϳ>K&&&֬YGl޼Ɍ1!Z9˲{ yEENgic$/-(kg||=zjjj`('''%Dkڶ} \[, zeYFǃ$$I\O~ۋH{{{1LCipXu:tb~8N =}>_pel={8Ȍ1dvx<(**ʴd2鹙s+e |霙AHRҜ~?OWWp8 ,֭[| c va3UP(j"d>---ǣh& RF)9`#8VZ?3J&at89"H%%%Mrpq!7~GEES}}}p9qlnnf]]]h4ARA9 u裏:rrb/c?&Yw}WSE뙴.LgGpΝߏdѨ(M ܕ~硔߱c)0maܱcvuu`0M)巀;3w3Fӹa㺮`ma:9s+++!V]{t㔪<uUUEUUq``.]!n`3QJ^x!L&\T*T /`0py} w*kONLLT]6L)%e^%mۆ@ gu}^QV`vŋemZzWӶSNN=,T,=džy"x H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxwx6|?l_޻"pŦؘ;!@!9)F'$9$BM(Sn %wٲ%[kUM{?4zv2s]5+i;ܿzx ƞ 1bǢغ$@7uXƱf,UT ؀=Xv6cY ]7JXnzqYa<kThhc~].n`sdp2X@i9l |=3uj,2"fjsۿ$XC @p !0bUfyqX.ĬzqeV ᗰTl,w 2 Ib4]ez.F(>-LjFbn_.nze7?y,;zq֑ۨ @jbjvYcX,=cM{/VXl+ZG>lkb>F1]3eXy̔"*Fr[, ԋۿ$X`#n[_vqWY@ky?32 xLsQۿ2`X~"[@'օh1 U vqWbV#Œ1FyN簫_.nrzS8K82uS3>h/Nf_k$%ſ%?|=#P48=Pu h/Y`Mb ,i.n6¢Cjn4`\ų1*Ϭ溸]0wlcD$y_}9>̴uÀ+YSmUs[U4`:俎ʨ]/ZJуG$x ,: P*Wn[POͬl$;Zϓf1]1W%z4PUfWy@U-/nM~\P2+>H.;sC0JrF2 xghuG^^!`9B(cFɬc_E,J3YDPTIb |ĺ (28֫]e}kDgچ ӏfaI tw?.2N} Ք䢴iLҢϙ#[[PDئ * 6)1T|,KtƎ#|>7eJTfdyw̞/ڕz8 ċV>a`1aƽNG1wv05 N_4^&@:GeBN@q1\ǏO:Ip!Ov驪e }}8}WtSǕ^`ѣ[ss9{lztK[ѣ )/^δWnۖ`0vl\~(ݸ꫕&Nv >3'O ]Mvネ¿g0چ#MC8@ԑ>k_rQSusNcWx?u%sn_%%&'㯷vR3/ҩ[o9x`ye%?{窫tbp"NN7~㍸S_uIyy2Xחvɲe,7/W-_gz~ݠQ/eˠO X?~554|<:5NM'>_( 8P\ uEQ֬:Ӆ捜&Q-bz< Zd,Q Q xJR/T~-%hIEٷ. *S]?5 VV3gl6rA̪`g3QT6lذ~=NoFW?>XXV&7`kN1C;yslt\.l9 {[nIOW%'m>G47v.&\jl6\6s5|b D+.L k}4eI[H{ѴEA'-2}SȦ/S'ȹx+<ʀ Xcy^+Bpp}O~?p\yG>\]Os>hWbӧhu{-/qe5 ?WV-K8E@a2F8_7 *̚ޏya'@6 882:JxV@ta߽1QN!2&1 >| g~ZWWQV=UP _\+߸qc߿-KK^?|>,^Hԙ['|+_ vm߱Q{饩JJ@d6Ii/`̙ ؃ǁ_+_xLxx~vyv 瞛Ie_On&ZQZC\rY3~1R@CɬN,R)EaD1͉!6s"ɳh`13-ϸ;#?´O]}u3puu!KnxR x#sO'M"w#.?k_]=)Gj> w>8ҁ} ?*YNh?o~b~;W+{&ܶMʕ(y[H& $ۿ[[.lo믽|v饛Y82i8Y/裊Y>˝'NpӮNaVZ%7 L+_iΞ >@nJu}bR~jU^z g+<|{ʶk۶廎_r6gЏ3woo/ZFxqqAv-1>zWW~= _z)*,6U0(+AQp%KS`Ǫ0et1 p!ISacMx/՚bƨkL{衇2J_im6ؘ6[Wrqq\wc#Ν; {"| 9Ν;ʵ_""?W'0vLO7VMOKi4 :cPԇ5 6/c1*ϴx%$/˸?mQ@c: iN HR 4 @ENda@\n.-zeo5'gXRB8~f `<'M>=|ԩHAiJrsSyQvu#Oܦ(*pԈ[4dFͮ[b?8a N)&5>wf(0ET]u7~xNC]\Lܹ>wh!%'Cݴ GB!HNWn;ʴ"r8o_uŔx3gBEgbŮ]zG\|x=MNK|61 'b_MJK񍊊Sopx<쯷Z3ǚ5N'$=x]r|R7yrnY=u}4h]"LVۋG5rNKC>ʇ5n3!z Cs* (FFo?Tbט`w=暪w=]t X0e3O`sp+['w'ك^;nϞ`}= թw׭&JoCUb Y& D, `I*fKW? zkS/X} 33̜9mM#ĸNz⥗\`OLğ.kϫCKȉ 6KGܶ;p<Жh/[A3'_bx@嗟k(,Dejjҷ~VDY}=kfOJ‹+WW+5(BӴ!v5jaVa Farf1bGywbxrˆ~'j l>ĶD 1n׍?2u⦅~gpb/ cz}E5@@;7TW۔>Mp_ꪔٽ=~M7uv{Zlq+YnCb{z6'z+"fMu64'OV/K5kmuuu@]~=ffa!ꔧM`~>+4 _pN40-)k5c9$6IgXNtɸd-;ȿ<9񽲲sz۩%KҜ΍K5-_Y(55Iɘ^QHlh3>c 9gWTxZWg3@<ِZzV:V3z UئLa[gθxtU%?־z`?!BRorFFuso4i)6 ؁6;pgÆ/Ft 8J=z(yO;cV"+.NsKT@mxӂۯ__O>?K*E^u ]#Aq3jsSxst[/a[ W::SԈqǎk>tLS՝;w$aɥ*+~(5IB̞=;hjz%>Hj*d]_Xx.#|XWfZ$(vo:!|>5>/X=" نk.v@ف|a91T2X.8T=駓jkՓgΈ=XtQ ݻv +.LIK ZZ{aݝw\?e') ^l> ~<׾]1) @TUi1iXMl\U"iD9"ZdduƙƅILXln7(f3J#oC@Yv {?A*wG}.]DRS.8 iSmmO=K=>PumȮ#Qjt!F!dGW(yk-VP@t+w_0A@2ر 9 /V9?,X3ۗ^򴶶?A %%EU¶mP7vʲpw[[B v;B =DjwEQ@jh ]hh?sq&odQME SO7i)tclx\-J:x;AZB++3'T^aҥDKJbe5¿mɓ.R F9(avGhF3ev(U^F ZL;uwNpzb磻 ΜZ{\Ȑ9cW׼e99%'o[|yM;ْ_ϕ1^Q'^Q( &Hŏ!0U`dBpn L bM?_;3~|Po__,X4::{+/yl_i.ʾCk`0(oO>ajW EDz1XEr+9LjdX8ڇ0NN\NR5]! vxu7;x 6.\}8q#|[8}ǽPn:^|E{(Fצ-ΜﳖF!@yW3cYfzGqjbw,>,F-2  %??}_⛷ ]!XzO3fa۳& "y (`*hf\)<6΃PnaIz2 f"ߧEm:8: Ks Ps.?hn] @v|<I*+M--ygtO Ɩ %5m޼IP:a6G6}ܱcq8>g5Xc'3/d[EbT9EU7hs:laFkUQy0p,r:@l3vCC8;gCVR_ST#*=Ӧyb1'TP <W PS#RE(BP}VhtLWUBQUȺ>T렌A2FaP*s0}[_}U=x~޾܉qBo'}>]#~c\r|O^^Mnw ~̟0A_H`XkM0Ɔ*TÏ 1 ߭Q_)&"z!Frי[j^^Б;&a3¥kjj\XZZMSԴqd5$mO;B0=_iwO/*b\5*`%VkLNQd,ѲAZwi=gڨZuU@V1؆4X0`aN@=uJr:(npkia,P HzQdg;;;1Dd]VVذAZdwjˋ_r 2֭p?zlw ^?㏇so?u|N=c3Ƙy48iyӘ PJTF-2yRSՙ66ؕ;1$La0 +DHh.iDRU3]}&ܐڗ}͚ۅ7ް)* "\ enTqA[{S KČVIbXA's@5ؕh1eY6MbaMp8LBBhAC!%Z\!!@ n9sjfhyQ $k 6[пj>c[ouka =oox $rdGVVü،&jhr9 b1Ld >*cTS33WzDԤrP+}}X0}Ji_;hh쒤%\Pr=_Q$18,-*#݌rRP `A/j2 L$PJb|[SUXJxv5Ki `I   "(, pLh@_Yio,Z92SsrvOmc#Y;o^(t]v6 $zrW=:'3"麪bIib*%IbfԏRJA`K~g5A:7% ch)tDM=Z|S5REUu+qc/p7ܠUUX[[8{zχh3kO@_sMG7t-zֈ/@Y=̰XtȁV Ns f5YO\Љq7X VY%˲$6AjP\. I0'Ǡߏ`03#A@%1A^S;YScvfB=u&'/{eŊk.TBv~>T]cư{ ¿|C'Nؿk;J p2cJ)Ůd5/YQhFؔ5FiAZcS,6t6ked_q3 e0q8A/O|)* _{)of\~a䐯u=3NA5M"#My1RO9|哱‘2N@13#:ij0+5"Ħʳ+ }  N.+!h;|PgϏΞ<g6 ]Go_/3F^/zִ%vdӧN%þ]֭zO_~qG|VaǬA'UU("E.|1(Qhj?Uӧ?JLLyԸۿ 敖_v7H;z(NK/?c*};w/]R}7Ŋɓh4 @5f VޜscNoEϜϛ'Hb $I Zͦ&Qu?&bfո k+3Mb2X8Np8H0$88 uV0h~JT>vr}y5]:g Y i}kc`1juuCB8DռRX(Q+5kj׍ `QJH,J:UE7_ɬ0# p0Nv;LbGo8"CŨ<=֏:ew㍡Nr'@pٲ7ZQw7N}u啔9cƠkz)/'%%$<+{+NU|qWmY'q9M7y_~pաG={w02At.ܰ{c襅nQ_Ll⻣R@.R/diuͦ:t(Kr\l>`BFؕ3 Z]aSc,Sv;e`6 yl<,4@ ^dsk`@4}*ʀϑ#!~'Ȫ&Lנ}}HkA+LiAi AQA!3VZ@g BU ^bMjRbfa 7JG`  H .Wm~u];vLddg&L߿m&lFLr0h65i5eCy|o:`mF @c B'Zj-ڈIg23Ji$t:#G'%%_:{+2S^7XZKu]RUUM PY$I"iNm61`_6)+yHAA(f}hԨϦJ0 ϿxOT߲3\F?dfi Va0#̪y'uDqFj*ϮfI ^37c!PUTu=*Bgw8 v%\yJNN8f%%9Y}2ƠrT-Eg&a>D)EڵUM!l7ddHHK:[3bJzӄD(7TwɨO0~6r0/S9ВC1N v 5G l3Lf nĉdF("IIIdƍc$˥^~ G43*jF XE,AEj(GS#{Ae I C1ɢSu(Gi YY݆ \rc+G!F;ɮ@xp_yL>alQ V  ܸ΄7yG8vu٧}X;ةS% s넁N>ڴ ./,5D^-1"2fu<yF],j:^)5KPH1ڬ,~Az!̛7Olܼys~AAkXYY7iҤZL; TA7f-k(zf%A{K>R(%Sn싪"3b  T0jf9eiCk9@GE? u80 wD D0?YƾӮ.;,ZNu]'JD'N{`0Xt:fʥt]%AM$ F|˞&CM70K Q ]*HV5i_VK%MMʨ)vUoW8F<+pyMLY r9r󱶰oV0UP/f=aG++mxo+)9:pA0G̃T 'J*p0F"4G} I!gΜ;w&˲9VBl6@ONN$indYIuu5:::0{lM4R7B!:T5ރ{2o=KgV˚0'NEhG1)^nԁ=œY? _~1j1 +̃jSJ#Alz%LUUNҗ ̒AG! R h ^+T{ %cư|\j\}L<Em[8ᙍsmӦ7=%%.{Nry^`90iQGIK0@p_k=Tttt/\0vϻ;;;m1rϹs\-[d>|8#믧޽" r&BH7!D&!aJiRBhYnf:"t@gu5!5 !N#x&2eCcD%\#0w +Q+PyVV1@ź&Ʋ#!?k1g) 9{V;{V``9'x2eQҽmUUU’eԜ<"lkEӧYk֔>qĆ1cHOAW1J`E$d1}Y˳lL3U%Xt]'N***+V>^VV;wn:1 x@^p!9x}ǎ+V`RwwPYY\QQҒt/^LO?L8ѧiZ;!RK6B4.J m\ b_T|6D #^ \c:`Ӂ\ƀ-}#,kFM4M#(2#}Ɍ6~%6%icrM%2S2Fdfk|1< @h|>^Xr%{G~zR}}K+**̨s1rH Ȇp8%B!1&Baa13(c,$PmCJ85͈+R] *-oƬ>ƈ9Noc~UG :9tduÐ?;0.]JN ڲp߸q9IID_=y<{T:.4?yсF:o|tѤIӧ] v > l7ϸ Й̫8{$ڧ%M0ǰQ0_ф4 'L7i_|{fhiiڵkq5(6lHmm-INNfgΜ˱l2a``?Ŝ9s⽪j<` 17o.?{lvffp-. G SQ!P-&10a 1`,ҁweLcf\ɘgFmsaVUchk{ɰ\&Ej)72CAzow-}ާ. i49빅 R  _5Htz<),Tj, Bi|'X X5 ՘XV2U`,bXB-3g(媢Q~d7?&JM!q{LuVtttNk RJ@|466+Vhq H EaNSnooOʲBN.bYY~?؂  'OL2崦ivJ)5*>NF,&hI#ʗB E3+eQxB0+nP~OJb r7b$Վbsc6J걊' aHF :q}I,Ș>]n_:}„¤Nf́@{r`?jk@Rq1\.ԁw & l/ht5>܈|)l7'l8r䈽k^W|m%/29pqqޮ{<ѣa,*200x b6x{x oMM -..Ƨ~]v%%%9rRRRMzbj0!1_b=&q|WuoU (;a:E|~YI7QbŒ,#}VE=[SN)5Y+%55|f^|ѳe>4kVlMuu(22MIW5J(p"_𹼼g?6!!qaqp ,G<M  ÎddDdF~Qpxu:rEAIii)ioo'7oF~~tuuLbiiiڕW^5{@kk}ΝA^^n@uu#//OCwvvv7;qB`㪪1ѰDD$VI #mcZ@D-+zi2PpfhFj\~ŸʠsOb5'53( #j(YAHeii݃RرN'Ogd㫪~?u*kko-nlg}%,ُ%)b8E/R $r&  YHEz`yqQ餚s5я?N?cdff,u<ܹsŃrcǎ 8pO ,K dŊؾ};cw_ߌ3TWWsΝ;$IE2@*JͶgij S$RE웱FoWV1i<(1K֒7G)'! Q8ȨXu"iPvHn_$wo/sCY=mmFҘ1>~8JJ\G}}曕W֯w}$>=[ƍ{֎^[@&q(1#A7Gtbr b-<`nUQuijj.]M8t:EQI8Vϟ?/)))>'^{tϷUUcL4-'455U!i<*cǎ"Jc֬Y600 LdUIM(QbT)#H{bkT>Zj7U7&^Wx]پ}`ٰpB477ozEEEvr˂ FON:8uTIݍ7x*C4ZM`wHrR|P*rnl1bV1K0 ł^E*t`×5;f)h|pyG:QUUN(C fٓA_3CH*0#Bpìz"fem QujCZXӜdz܄btX 8IhPWS8a­wuGgi Ga5 6s&tBИ%.p™39tfȌJ&OR*xSPa824&$ ~UbLrKCRRVT9y$ݵkm޼y@ @0UEY||穧"iiiZww7]v9sGacǎ6]5ITUUEOSB|즛nO:5kVl6#N*嵥̹M$3h|HTUR`F#IPPPy5kT;E*T@2l+36 )O[4e~Ŋvl .gjP^KUUE$I25wLJj05E3CG7r#V!\7 &_]>{6'/v[xc4B~TUU߱}DU[o=5WRpছ>^__xҥӟ\--XrٳE|Y!g~OP`QNyAQ>D;s:,80ѠNu]].S6o,vwwYf555l%333$7d=2n8ܹ֭&%%yyyZiÆ ¬Yi?~cQaC(?~6v1cjS4 lϞ= 1f BfqGQEbt> !i8bXx@7C\ VnOU@R `4 6#/ˍ@裏)*jܥ"FWf.gɜjA5RpD753JNe1z|FkkV{zzhCCQUN>]$)TSSIHH>`gQUUp84GDMM#U8?O؍:B8],K?!EҢG; :aR$Ihp6IJ *.I1ٖ3c.o*G@L@_aX FQYY|Af0@'.Y< IhV03;mƩ./\23ieP@Rޞ̞6|MY8$8e5֪0:?ZhPX$!:a.pb=( ( >>^i$55U)((PA`jjj> INNֳرc{gΜꫯ混' eee 7*@)%﨩I ,`v=|>h" @$:uJJHHP,LL(0_<U!eH bG (Xnj XP2EeI4-PD` xʬV\2Q{ EqPEaAA4}5MFi|g-ŮyfXZ(٘} RɐI)r%ͫI+,kҤ|buսg4ϓϛgd 5-M_"==pq~p}"AMi_;0!shl5kɓO |B? nN茁 #|1411cǎa֭,%%E3\#_m~!e .(F&LPICō;O)U;::NWƎ4MVUU1'NIoo/裏 U,Q,f>Ϯ|0mD!&ȟYh1nB 3b -@\t`iy~ma(!.ĝ$A X6MeYj-YLa"3k3y}932B *$D (嗿eU};w;[[Ůj8~|xƍÇiyy9KNIq_+(MvkZTմiKz i}׿Ύ///*++ZwGGٳ\eKOOLH┾>qӦM¾}&$$ES9sVR 5Kc,@X*R;\c;Gzg֫9pLֆ|S*tIpRKu}녚ekC4AUU($I(f, YE21g.Ø1s4ظZMtuQֲ2܌MgXz/.+.*ReY ^Jsm8wf}7뾝QT<}==?_ik#_^w[o%|>iZ@HH )!p8kkۻΟ|T[v dT ?Oob|'>0ׅbd'|E\\fDiz  v=un-##C7n`n@ @njYGG'>>,7DOOe?NKKsП|I{~~]E l dggL5 Nr(i=&CG dMs8iZL ZV$jf1,K ("`y0CCGS!$@颔a$IA$2>H0j nmv#LcSiѪ`BFp#}rsp8L^x%c'MR{v89ii8(5gΠ?%qõ>.47s3c׬j|a7oO2e1 YrJ.z?b+~ gD!+|^zby1%d|VE8qB,((~~ \.TUUl۶455;3&%%v?Fff,IfAUU3z0ٕp|'3k֧k1bG̫+ 95Ra"K:5 [fhJ2_łcٮ4mcEIPUթ(]QQefeYMeYi3)̳ 39%S! J2.JP]U܏o谇~zm8[_oƏG (a{ZIގvټ^/ZZvfÉcgO:EKss5[Y8|رOJ\RXf leu ʐˆhhPKKJ쿙Y=%VQI$IEeD4c(Xz\ϬiG7(CAMbY,n`U$D/[6ロG¼y4]ifQGxWx'NTݎ+V(յYg\TL1CUQ /`;w,;&.{tݎpSd]?~/6Ѻ:nocY!)Tͥ&S>Il^Q=JU1(ftyyy먫]qԩSuV<#0a***pydee:,^iii8qy2w\ZRRB?T6FR4jH f[gĹXJ '+bd&,ňǚf`,A)ʛ˔Æ|H(qH2V r 6 ,>jL1P`̊#lnQbYz2*8`L삠v̘ƶmw#eLx7mgϜ$N?.M8Q),(rrrȸI&=֎p|Һ6繹`OB(Ŋ[n牷1\roC78YJwR9gV]W_9|.\P]vm7L"g1LbSYHZ)7BIQOn꽲,WȲ .Y%fB8`ݮl6AUU_4nY/ܹө*lPU 46 ~pxȟ Ƃ 0yx. SgP58gɒ*2{d6? Hzڳg%k 0)hju\s4\9{??OS՞h*BPkg wE13FD,CG#0|!H"@Z`u4fwCd|Qa#AuC)S/g `ۍ6 (fas. n8{Me#aۦNjey+ ժ'v}Db\ ]G}A~z:sǏ[9gdpsQSKKmkJqKOWWΜW_o4pTd=4qw5x]]6nٻoa~ʡZOV8=Hw{kTՙow_7&d$ۺU#HM*薋+22w\Pۗgۤ$̙3ӧOKOn}Kbxq\wuEx[nEmm- c655ᰠ*u:06 :²|^XuS,%2ZawhqbaH6Z}65ͦI' Nb4笫s۾8/_.vtt'NnFl޼EEE,UWW;t=1@#dNJzY1i89#5>wѲemcȼE%eeΜI"=}p כ7 v,.KNe|Tx{nǖ-k23]Lakg?󡭥y s,Z4139MyyҼ^Еm۴쮮P61j,A42 K7Wp`[-A)bMLLƌBȱc?яhnn.6oތfdggcڵx<شiS0۷'N /_s5>(M#-~t]7Knn^oضM|%Ddޞ ޿QV2lbS;M^nE󑞞>~a>s^uU7ۑi&5556mEAUUa]cW^HF k+Z^͘,˗#*Fn&Q =rȹ}%:=???hFyE<Dnn. Ǯ]ЀI&aܹ8pi4iҤ(8Np8`Np8 Np8 e(w qP'jtߑET**A z 1gq^x?Y9ՕӬiUOԴ`b~>zϝCb~>2M֬ ]ff*sD&b.ݒJ:W}FW{e"777;f͚UUQSSCrrrwvIIIΩS"55K.uۿ[oBBB◿edddW^:;;kwu:;;i&ddd #`1F9ohĊˊ%FNО3hn ?¬krYF|ƍ̜9(,,Ļヒf|vǃ8-11Q34Ōiڑ1D% D0#Kԡ0Di_8,_J4~<[֗'Mb33{>aIDeB2F Jʐ-AU@ [[[`W œ& G7lhH麣1>;_hmԩV_Ӂv=O}* K-pGv,Jd[Q&Xvm>}:ZZZ|RyoNΟ?8vX^JKKcɶ "##(ꫯ=t 񄳲UUG9ZL(va:5MŧJ'k?/9Q֢c Xq>(]}Վ$ٳΝgeeI|r\~/~qgΜ}ԄcǎnCUUcժUp\{O/..*~_4 c rAb@id0  gΨ^ɕphiiADP8^H]3;:3lkWU/5|ƍ8=Gcwt8T 0-]bukʿX|BeYFJJJַE322o4f%\2<.ߏ.  A088(L2%#n$V&FG2 NIטcI̙OQx[pxXVHY!EJ2SP ܴ &p K'y+V1ưsNL6 'v СC4i8QQ^^~_Wk׮>]^/Oﭮ8q@__ `0H5K3Aj861x>d9Zb(3lR_s@(DD;lC&n*2"?8HTUmSSŚ^ho,`qʠ3,>N!عs'2227o<̙3QSS# 1aaY_JlC7n\pǎ>)SXh, `~YL 0ƈQc<"r%Yld9uLG5G&XZUDưvaݎl<AY7HOOo~Ǐ:u*Yۋp8!Ipjjfs`L5AKLg!+ W1Xp`bYʁ4>7LYC(勮B2QQlI \uجъ (W^}K_pY@7o"11`Ŭ,UUU"l6w^W8&-QG21G^ I^Lu4Sɲ ՘(arJD*58ngCC@IO].c Ξ= UU[r{UUuĉp8,\veDQ$6Mb6Mlp0l6nr Y6v8vR4 `HmH\a `}OIKKS-ZQJq}߻wo=#(..Ƈ~|~y%Iz>))麊B_jjhѢzrellcfpai 20$ ^HhxoaP4xir o plI_dި"AepJ$Ip8l֭ӧqqqNײe7o# bرCJJ gϞSE Bfvu^'Z47%J@2rX}/HIDk@Y=On̙3gΜs3f̈,^;uI?xn{˖-mǏo|n8|𹞞Ǵiӎ'$$,x<ᅡP(>x# ڂhƞ7#q. ByLBPh0`(P(YQTUM);i2!&h6ódFgQW ef`:+#$\< ˫~Ě}y<x<ٳ(ݎj?*((?䓚c̘1ѣsŸqс_WHHHPldFFj P1JiFL[3c 6Q˙v42M?V3T cϊ1Lba4->>^ݿ?.CQxLkkkU]]+>>^ovTyݺuWZ/55u(?q\^QUUEOeY|.+pMZP+ BG( b9Ơ¯i  Xb (0~y\ (u<1Ę`33ϙ1!\.V[[Ksss5(--EffVZZB[n%ΝSE(((@qq1 -- Gtj 03e0xp1` K9@3JĬK-I1VQLrWĈmgM1;vZZZBw}ެ7͟?7{ &8<{, =G ف@ૅ(+&YoWWW'1Ƥ7v8Njt:uɌ r4,c\.vtpH4J!ǃ+ @h+`=BI4CqM)EdoML ZvCiFE!&Lhw8ޮhn[OOOWӵ!--Mmii+&&&")) ɓ'&1]#|Ln|9U=֤9d >.x8]GD6Hfl_뾦WDQ|.++;osPF5>S$&&*;fo뾦w}wq i&O]]]x98w\SFFƀiB= Pd\*2e~:88H0ϰ$ \8&ppȲ s9\UUT!(bqic5(_fIF !1A|I<@|t֬Yׇ2twwS'O6ol۽{cauPJYVVlCq!+8r䈲rʠE^Y,LV5:X&s2CW19faZ:uaf U1e)mjcÚO:IOOޥ^C7n|nkhhplٲ>mmm!׫hllă>t:6,uL:d޽ەwy6-. %\y瓒|ÿ4M# v)!!AKMMUP(D9R,D*dEb1"RH$Cҗ*r[R(3TvիW ?3g kr[omeYp8zEES$,]",11K.ٳLs8i"L5gXƼ lb]Ԍ%jYyUQ/*kMX=UQ .og}\bE\MM \s5 njkku]qP,WyׯǁЀ1cƠq;wl7oޣqqqEzzzx֭5k$ddd`޽Y_}R\\,j;zhQSSu)8ξ DQȲL0cX"ryaYkg1i^,FyH1kJLun(riBQ0p7dggM 6lzW.]0je/KLLTΝ;'}'(//֭[hվfkg39"3m,%Mm3ZW^^]va̙n׫fddg_p8˝~<)Sz TQR__oB$;;[4 maXyNirEkX*pJ0Y?$A^nΔ1^όVWUUsʔ)X`Aӧ#ﭿ_ s=n2e o̻[ׇ͛7ۅ$;7n\ XOQN経Tp\0oG; # C*ݽ{wbJJZTT=z9f̘qk`5''z<<<& 2{E! vt2./5sWE600@͛җs&INnv;kllϞ=k?sĴ4i稭Wkkkm۶yKJJ␢(?O3g0/rUUTf1S|a3Ss3-FG3RD#kF͟qٕ׌H.]zݺu:Ye](KPPP駟&+mۺ}ݸ1cƄN0qD~A||<ݝގ: رcǏ#11Q:ujꫯ9vg׮]   Xf5[ Z;"b4rS4 Ŧ`w~/((O:cȆȗ]vYܹs  vcٲeXnDQıcpW`x<0M믿-ܒٙGs=^]+ófuuN:uj߄ SgWrra͖hפPbbk``lHn (гe---;ꐝ䨲,*ıc*_O z)-==]ggdQٶ6A$vYڐt|K_.\n{1e[lꫯ*Bn:<sѢEx媪* kƌYLFe҈q3o͋o 5ǘj5yzU#O&4M(*h0TX{|-^W>x`ڵk*~ztttpý ݎKz!|_Goo/sNFǛ>]III-1;;&L(0a…߱cGީS/Ə뮻,NA[ZZ6lؐiUUdgg UUU;vyia]׉(TTUU'?b_|9~a/4 ɺ`^J$I0&ӔY(N<֭ïp8L}>PRR"?p8:{NN6ydѸQAk}V $ `#d ܹs===o(ԚRD@k֨h! VjŢ.d&R}XX٬ Z̢ m l-++&ݱr3)))7o<شiLG(톮|hhhg}[mUUUذa͛/͛ב{_󹹹Ivt:ꫯo:tȹ&wKKKٳg,Y]zD)llltO:5;00PJQɓT׫z^->>^z-B͛'iTWW+fpvwwcƍr9>>^sqqqZgg888H}>*)..%EQ}'H HKKB$1^ C9> uuu裏 O:՟A`Áuaǎ5>tZQQ᫫sj΍]،[qYpF[,,XUP"β嵣'cNNpsݗnꪫ)(..ݻܹs?z㏱k.|Gaa!t:Ō t,\0- 8߿?>>i>Fmܸq1c`ԩxW[ ~Y`D?Pgg'-]~姲Z3;EcDQœ nٲ%uǎ(,,ĦMOnFݻ=t- FmA`4+ު*8}m6T<|_xdƘ-5551*eܸqrss0}t֒ԗ_~9"ח!UU )8 %^[`TYc"1F0hV أn"bW61h[wwW@f,rj|,ɰ0OyuGC|)Χs4`묭}v7xUWl'Olb ,WVV i͚5>}:~߹#'N#4˥]s5cƌǶ'O\2nɒ%vOh?>Ø1c0w\tttСC?~<̙{᷿-ޞ29gϞ=YTTtsbbC݂ lݹsOW^m/+++Ϙ1cl6 III{SSSZŋ;vhSL鈏trbb!9ӛnI@RRR{ÁiӦa< {!999Ç{SSS8UUM[oappjyyx7AǎPVVjll H3f$I썏>f6(IF Ȳ+`h:KrQMXcL-a970El tWd'8qbs=$ K/M.--uɓq $$$@4,_\nY(5csss#EEEnp / _b7p`IIwժU ZtttdY|ᇘ0a8sLq˖-cg̘Q?q-;w>09Λoe0N>'x7:NbbOt]EK/   (//с/~HOOGzz:CJXpraΝطo6mڄP(L|+_q W***l2|ATw8= 3o)gRԥ+.L^3{iaqbM%KZ˯LXQaK|$gvyLӀܬf-// 222,زe Ytib}}=z/~lʔ);N/2&Lзu֤K/HHH֭['Nn*Y=zXnDQ7w1Q^m>yf`g |XA?4yi1Mӏi%`mR\ڭ۷8| ZA|<<v웗s%kfy:}}{AMM͛q~w``iQQP/lGGGݟ}`aӦM/Ď?ZSS===[B  //^ ;w>Ba1LLLsoݺe677#H~?mmmN2Y$\z5tϻgHII>yF+  BAAZ :׮]vVUU|`m/qy:qγ8sS>ćnX {~i|)o@kk+xޡ/ھ}0[ۊbo2wށ@ gh4+ۛ8¢ѨٳYh,ܽ{bAhoo{uTTTFƍG*++}w_ݻl2Z]]=V__GqcN25BtRX6c,1tIRJ]RcC*P Ab)K6}4WɁhB]hWy9/,Ɋfso|rǗBhjyy\a0 ,Y2а _Z3aÆ?iii);}tږ-[L0`hh^|ĒH$>,طoߵ_S)Oj.r ܹZZZvwypttԌ_x1>Z[[oYfp'Oq…G6nܸ }***tgϞ=7lϟ|mAAcc#ܸqz[!zj;wL4۷ H PWW 9pΫc clcKRJMJ1fL)E!H?ֲ,$vA؟#[ks%\Ǧ4VX2==/.Ϗ {T.%lnn6:::}>ߖ ~ͥK͛7f 뮼<1N::::ݻBk.舯G>yd$n:|2FokkZ,˲eYFk׎qK>s#p4'''?,Xzu֭[-ry[RRÉ'hZZohh.,,,m%իK322H}}oB`۷og֎<?VZ`ז-[݋-JN^:p_BsaBYcBa-JO2cߟjc_46a.>';cXǬs}]nf{_~9rܹuuu2֋LMMeݻLӄÇeر&''app0IݖeұϿҏ?Ƞ;w<-!UJi!d1MqY1A1+[dYĮX-mCO\1ǭTq 4Y;6T\\C Bcr`(}'… GLӜު?c !!+!TB۲,c-2[lY$pBJ!k<$@6gI%=d'/cLǬuƍr7tuuU ~Fyq\g1F-anYV5%vU [w:PcPCG5UX8ƭbDͮӴ !DabGqOܼy3% nkr/;vbr'gLW(%[BH2I$ȅ4f])e3+:pA,L$`zzXޭ\F{YYx$zɎ;YM iTW1T N{9?}ͩKTf[9娅6tIcűń禦Bd kYKư"ɄeIWc% e)xiBLk&U`a4@B2l]ΙX3FTժ^VJfJ7O|,Ʌ.df7\Y#"|)ؓ1iNt>#nǻ`I6~NUc^* eREMӤJiR*~H&aaaHiЦ+Zg/VuչRU]9d՘ e97TeÈ,/lʾ$J.+?rҖF%W]-B54% 4&Ƙ[25NX2Qǥ&- 1k$NqЋ"4=Lle HW%i4O*PT5$|I+_*\1Bۥ1 '010 "TvbmS?n+"afIzpMV 64/Sj4hc*e%uBJn'}(@Z}4a=a`-1uyR|dp#BqXtf=hh$$6\UI;$x22&!kh$Y-'UɉfSʹ_ɪt>)d4Y54 CUŜ@YV`Иi 6]ʧ# iɠ\K|MV g$LJ9w{5ι&L,,NvG~>W}v3ɑ"SذqXk'ۿɪHlιGxKO$: CdWT۱c_if'=dH$ITȊdy,֜KiT5Y54K1SKEiIFUh fQڄ֮Nd`3ƖJ*Άv"*1)|u8Uɪ1M R?c%lI֤W2pXQYޘU9[&ƴ0RIU`d;IZpW^ =u'kjh!0@ qRRJN:vhTUdиO=BUݔR7TYC'Bbc)0;K@ ;\IENDB`mldemos-0.4.3/MLDemos/icons/line.png000066400000000000000000000056261172143270300172370ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxؽ @ 7'6djV@b(%?ɵn&!s$O X^Dd ӆ+n8ߓmL, E\4ᢀø*7p5 ܌Yw,*8+4&8- xYഀ+ \Ss 4W3IENDB`mldemos-0.4.3/MLDemos/icons/load.png000066400000000000000000000367301172143270300172270ustar00rootroot00000000000000PNG  IHDR\rf IDATx}{}7w{wp %Q(29~IvDJ\+cW?q\$ت$N.[N9I9IU\%Yv8NTd*$e=l @@$AH8uw{w;3?fz7Py߫{<fq7a|a"QV~铈D$c NX=z=w~[m|J082dSOƫC6nv Kpth.a/TJ4Y p/xt;t:tљ:XZ\DԷsp p -ϻ}Ƿs0r|3'  t 0 ol pnqJ';6>P:py<}X? {QW PpXlxcf+ m5Ⱦ|ưM/`g= ɨC$T-/(1A0 3BjE6y6<c H_VG.H `Qz_#ǩgN"򦝌w=ZXZ\BNE[Rsyv_+[ﻎȁdg:- mcC3'2/mVEz v zjNy}Yĕ[{82wƂ6p5p0v*\6 "U,;t_cGh#8YSsA8H%_XB{Ņx{6:'Au;>>0K&<Crq칓STVc^p/(y/g׷ɂ"|8Ȯs" VGx xl0E^"΅@fIi_~]^]G3H\6,*#sg?Cqr^ [{r\:M=8Ǥ`y! Յ Q P еIxM ` pi&[ 6❨޷ }n]u>CKjƙϟ_1x8ENDÅxr__I <@8sc~ڋn{maqV annR=QŔUb86Z}~ :hpOq uMa!M?4g>Ȁ{طo(1)Bt9Tw.^łYB _yS4hJ#  cN,-.GXIً>)|YKWwniߧ/EϤ 0h1) Gawn+G1}ojmGV2yz_NPL`ICC@II6t6f pMbzln_N=yˀI+esGeGvP0puWxqcˋm|Ch:V?z|{MțL8xS+M\ًCx*](BU~s~@怲g4ϝ;w 4RΙ7~\ =t$z|qW.!h?Op&d)||HG׾.^3 p|#`4C$A!E!UEZpȅ#R~ q|,p=|ul_ټν Ỏe_޳57%tOQz`MGFgL:;Ͼr p}8;n xT^sMqE{C,`zZPh 6(*E?ID1ƀF9{A$лhAد`UB9Dx5B%:M:ȅ_cD#d);"l<]oٷ3\ B;^z|S)XN ( `P* -#RYZ_eh}qZ.ܼ\yEMf1h@ ^ؤFp}qՍ~+.VXw! >c ,&maR.О EdK?~b%mf8ph۟~;^ Җq}FVtfyEGWW@)L_1TcDHB0$!hmOxb K,n#01"7ՠϗ_jw]XDɶx!c@x Gp@y)b;*WHz,IĵDPG.vsA-:N>(y€SLI@ǧvq2}OQ5=0{b= Qi~6JάI651$W%'SxAm]? IPcT:iX{uk B,RMU!gN[O?]9< #_XGPb |Kz_AC~5]i2 4 ` Qu?4Dh:BL<٧P#ll 2pP5OBgL0LlK{ڟ7 0K9P  $QJ@ :_ 4䘠ݸ4AGe&6hNjEU=S?eLX_$|)h0i9({Aye+.YJW*%=ԛkM#LĄNh$04gH(-ڑYde4%22DqO#(; 'uSoor:#`!KC_FTM<1ApغؑgT~]KOˉt&ٝ yqG4B7 0ψ1s"42 +zW^D_G% JNL'zrz6 12C ~^=Qń"@v ?L>vZ‛HFΓNLhԥ4O:tOrz[ ƽa 5&yby0pPo42+"@pdO|MnK(•9*l}[2ĉ02K@Ũ3pҴ:f-Τ}f7EG BMfT%(C&u.pP5tAmy 'ɄH!0u_|15s´X~(HA,|  T3O_!H5C[MZL/t\ȓ>q`\QbD!a:Jdžx-  ˨58#TiMz}NT4aB:i,уQU]G _G%0"{(]vSM%tK&EEuFA tS@a)\7/SH8Ҝ0d,G%Ƀ t4J$S@.'c9gN5S=JO#D@y]^Hb{Lq֡ EAEx:*Q%ceiŘ'}q6糐xUꮩcL[~J 0l#,8 {R&^,|_&zGODZ|[}€Ӂ*%Ť>/]a@/>$#gA5V%1DQ8ԌQ;"gN?RhKOX\D.LɾA(k@9Y1.`D0MP4_ ?MZl±8w&"o ~U֟i@V4J+mJ|ɦzq6^PL&!Jz"78?lP1MJ9(0͉j- K~LrW:0%q,!GݪalǚG3DPEO^PYDiSGa(w<;ﻹT{rP<꺟,/% #nOŬ2y!V&is7@Y'%lɘi'3GP_F $G(yAi࣐/,G%0M'lÖ&JzD e`F{ 3&I T:Ct FK OsJ 3Xġ(3HVm2d|= 7j-fPIZ@Y1I2Vy/ʲ>t@2\L}NV,ȨJ` &ώc_t.8Lme'VGr0/R/:j/ (s s22݁xJu8( s)Xv}|07-PuB&^4 UW G%Lx-{@53 ~PK/9s!6;#b-!>AЅK/&w}' GF;M,OCF{4N)D* ;E%$Sc##3<*V:B]W 㵺$FɎJؽcjjVfH}$]W1هPrPy\4!LؔB(twT9"5]݄|H#?`mW7j#Io!_J7u$bQ!̪B)6ـn ;s6hkACA&G{u&я/ɉnGJ%!MA0N:Eq6$ J 7BDPcI|DgCh,ƛtnN<L9,ŵ@P(ϧߘ#h? natӳC$/kgG)ڦl]as/.2"8H 6D0~d D '5ON30{^]s& @_+J `d{0D`~ SMCb!djc˗dsnws8,b?ϰg|22„!:~z<=gzÍ]u/^I@fi!qOw{KOZSyibJ!v}^|L|c6|G#d AU~|r 0^z/T 3aEقv|<;A6GpBFIDATp_VLZ6G7i$j͖<3 G>c'VVVtjy#VWWI?Z"H|v4g В@{6N`xwfv:/"*G<>Ϯ^>*el ќY4?B!7x䓿{/ qr _ 3eOWj| FV$W}wpPħ1xVV!ZDBb%oܗb ܍ "#sLcs&k]{a@%>OoÉlCpm D o}϶7Hḷ0i%셼Ej5?GH703 y=,S|nvGw܎ՃQEW.&IgDS-+][J|*aëz{~,_B;IB(O|$"*|˛qױcXYYbR. Y5i8 C`wu _f^bwb_'2üTI뎷qԗo4Dq;D$"MZ@?GX3-O:SqG5A`{8+||U|%VZ8(|B̠^˙i2n`?`r3O?M*t:DgZWU56Bxsg_¥}B,ε$I­b& [0gN8? cOiL> 1 ­w$ Vw:85\ك 6` ea7cf cy}GIf(:ϓy"A=;.k_y׺}=j1C q ?̖B cC{IA=~^BOS[%Tc ?dxkݢ?1϶:cShz{qG% han1L:{|Uoj\'m黒;qc^_h^fct:5 JuJ%4NJ,-J3Kj] =)ZJmbɱx#km` ~hk nW^M 阒 Bշ|q|դҕiq!u `PBE@Zg,""/ SSv;UQT-*aȰ !~G_{誰i|Lq"RI =Aj\ zeW4PԉmBf;WR?FAC>h4)XvyJ=9n (Jo:ftϬ-8&{"Pi@Wc!9*%<ݶn]y՝,CƼiˆMݭV , xD 'MOH"qSBSe5W E󝙷{tKX]go %* y=c!I@@W* d4q1? (X^wW,uƇ4D$7AWEfEr(C.p{xVzsooT. cB/Be28fz5]U6@Y5]/h8SNQ?0LPh|EHj7nk,'ޟfϙcyW|faQ$.4!AEMLKݺyB 4Q+˯3U,m @b_:uۦؖS+񌩀Cm {6n}eMj a bL@*TgUE4dre@Xۨ1U"N@(s@%?5h'ȴ>P]xV 0C^ZW,Sc$>MB6o,IJ~XMq,46bm\m#n9qu?~9vC~$M>Tȃ G`=M Ϡ%Q(p"ԍtn2˿BY_v3}FKnAn7PDg^ދb=P4ДgnK!٦|uM$a? eLU93Ff?d0ĞqRav4}u\7L s ˱ٵ@Yb\aN n{4vu(B^U^<`?ix{$v{emz\fN@XU-VP/"O'l&>9"AfA @5~^ OuC&0)PJO >"DuW43B\: t2;~s Yz`{#{*пTo$5W\vZpѪؘWu&;ڮQԽ kJ]v*ʬ&9 zaqS^: {"(޳דeSfea9tw`^R-Y|h~U}D$WJE(ugpݽ+J144N0@J"DJN01~'Wg*a\@68{<<Pt r_}G4z1FzoU}3L8w#$U}N@60@ o YD YZ4oaF<8uQ' ДbV l 5:#MwѠcϲ+O`ۢR8wB=~ 9Ra!¹<]( ԭWb8gij#kJ8Sւ:5D'Q m#C3&M &1VMi>P+p@D?T3PM@tV>?qb[N?ZG83@`@0}D]v0`Syo9VFwv;[waW^W ("q\'7+z}7lQjT Fd &ܼ>ÁƤ =`ȯ|6oۃK7׺&):B8a\aKOxCP*'>3 Iz5[`}c_t~mߌlUFF!(G\cH;K5(:m JCu` wk7X _}zwpRvQ@n:9. FTT#m6cN=V _ٿs}@}1n~J {_ŷ󍮿A, l- .M~'m'Z=OT;v'>>qBÂt ŶWN'= q =^`[#2Q \ q8^{wdϗ炮"1"Pϒs;r:א-D=M+->s}M.q@l#zMې 6@6 _8@H7,vd >n^[svB?/!Aj )ЉtCjI@P,ud(5'Yxl0vkoos[[[_=3O??ڝ0Z-XlkW__T-1aB 'qHM] )I'1vu/= /3:pDDHꋿ1>F$@GHsj9mݾ~ڲ`Qq4 H ;@DQS@U}<*_˗/OWaZ2R4F10MF K%D=>P0uYM{^V a<}ď! %K_CrOqA?Pchh@ Y!sTC}|`Aaxi֭'o;[@VumGڠ(h. ϼ~y C9!CČB,%I gepSkkkǏ0h@?WG+-T-o 1{*=xr:g Х D,J^Ĺ ˜hć)c*N!BTf6j _'GWc'GB{+!"줢PapGo{V0> kkk&^~qJx8 5 <4Z$ A>YrS@!mdpS=w66wmT1ƞp/UX?B4b][l!Jij=6k8 3D"{HSyp6\ܥK~x  c:֞s.@;v4<;t^z0_7ʟ;Ih$^`pQ %7h!U-c_o޾0b)D6|}uu2Z?^6`F|Y̱@ H{ihc<.C%GGy~nȏo;p@ w< O~vWh'!}ˏvC#OO~_oh4= ?GC8K P6o?}'?>XZZ:R- #WWWoStG yv?c u| _ş~G!ŗyd@L@ih ?#SOWO="G~W~|;VVV8pXŷVFV4 #CU@>Y& z_~ L&8HHȈH>"G C/39R& 5ѻyGƦ(L@rl8&9HRLwtcO1q(CV@71NɨZ}G_|[^?Lj&T-)H\ KI h_Ȟc" HC4xC:v/ K1=ڷ۽g=v4ޞ[h+YX Ì-.=4?0 Y1t$j ij@-{ZE{)xAC4B &X)(؞zӿ)T!jHӇ>I 82Voo>T]zĆWA ި&>B^Ɠclzto߄IT?$ss i ozR7 ͪ )$/jY`nx?#.f W3TS<+/v{{&d=yz@|#;׿_bz~tp?Y&A}=?\ ֠LJ#!hs38L&]YtAg㩿 .^ y<ܘuwϟ38L \-ݟw}ﻎ#_{ O";D bE̾INr&D@0MV8L4; a( ȓ+5iS Fj/$k3 g880880?zf;IENDB`mldemos-0.4.3/MLDemos/icons/maximize.png000066400000000000000000001177271172143270300201410ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxu|Z1,[%3c'qalRn|Jii'1fe,w̮dI^`k텡]>!AUU|=ELIIJ$ )IIJ$ )IIJ$ )IIJ$ )IIJ$ )IIJ$ )IIJ$ )IIUd?}9p~'IJRCUx #gd%$+*/ 8uHF )! ? ދo,=FDsT7 ;z=iƟA)~D֏Aʼnp—{{'uDwp; ǹO:.iא0u w >#'݆( ]7wiq_Yߏm\S6Ue;}U߸-UMVƱTEs8q׫uPM@QUSYh(y`w}'bre9jZ0%TڪV7;+qX~@( 7qBzVe [|!a_˩bƮA0*A?wqJ'ZW@h 8`=y| .L8}@DvJ4_@oIDaDRnA|wB>?fq8vm@69]sVּS{nQrAMSO[Ŕj=րM-5N1@8*JPY 6j"hD 0/ 0`}8(a ($o_[1;q,K`;]$f|q-7 ݝNA;gS ?`=8ݖj'=MiaqohiG D$`B*nZRбآl5 Ƿ;ΣJĔʲVtS;įQOd &jq@2KoXS M[a +a'aEgcEXMqJ>PLjO C *ȡCعNbCj+?Kɱ6R\8 'pً,bʧPXWŢ 񊠪MN܃@ېh0M`=`on[WDSz jкjV>0~ĕ<Tu @$?0? S8EY P X[p;( t2! CU\wC8#hMCk3y} V  jQ@,&ߚ+g[#qV,kgZΟĔd #2.'(Ƒpt"叿65Q3Ձd@|N+7qz[8,]D!,EN2_ qٝPrcẓ'hC x}A?\p:nl3̛kIh% `Rk?(D į~EPwV>TV`:[ LrVL"}]- F#POX|: `!ƁD| [uUYՁ@"$0}3e#1q60yl xqfv89ch΁D++7$ cq _[ʔ&| wd 1m<[&cT8y LQ5V1nvA[-qfgǹ3s +EO0#h{V"R7FHQP~#Ļ.n'>g*Xռy TXOˡAB€V`Bh N ($ 4`H 1^ QZ~C빣Qh^xg#61^]N)Bh<2p F:4l(Y!j|`\x˰,m~C+Ly80`&rSq `  ejªΫ*wRUR8D99~ bi`3V `0| dp3DA@y ŷ ,vn嬙cq;|()ns_P&Kq>&# :kU4"+-A#Fαn NZZ9s&s `[:h AAa0\Kb\5OUYz !xPQ e'!N'pU Bq# X{e ru $0 &` {Yr x@LS11rMvDjJ Ĺ$$F2MT<<m"@X `|?!`0ˑn(Flq%I)d>q`(LW H4 Yz|o(% E-aD0Ȣp0v"!Pۖc|p@&`̬Vq]^&D%PN?]A8Q&@(0@i1N$Zx^c@L ݌87bm8 (-={ד> PQLK=a"Qj|Xx`@\/VWsU' 2[@KS vͭ$SLRE5.7K]뵪Mϔ (N@5ݙ§ 4;'yOwS*))EvvVfJJR@R$$%)_1Z}_9'OJRS?8۶mcҤI\tE'q%-$K.p-[pM7.@Ru΅^c=ƒ%Kڤ tEQ ދ>m4M+Bx^(^P(n֩8Nn7$,_ > IR^.0P͆DE$ QevHp8L$F^UQhnjBF;np8?@Kgg'}}}\.RSSqݤD z8sIv}Tv$tQ(5#U/@g{;G`he%r222@677EMMM@UUf!l+j)F7WnlzzRJ }ttv^dܼ_zyСCD$SRTDIQ}}4ѣGq:TUUqȑo7?==[| +jX }n``m\ve6gF VUpew$$%)Fss3iii"IR쳺:֬YŋIKKd7VHDWшe(QPBDD(,,kE3QԎplfx~zz'ڲ20}I^rӐ) hpjv8 n]6#FdŊL6[oKnDUUէϚSCHW#hAP`>!RΫw0HHz9K$m-:Ț\ػ"3r+ô-˥[A#vm~\|% )_=kRdbS}>]}`| j?XXZYm(NV(@zf/Hy^άut; _p:pjqE} rQx{E*:::l_*^ I99rT|ղ>~PS~S |~ ̓xS29 *<.ܝ:g2\UQ۶1"Y.:.~ňR8]j@ͨQl(@+nڳg|WH$;v`ȑ'X?|eE, 3A!~ AcрweIb| h/XXϳQww̿CufBIh39XAkף6vލ(_ K ITZ[[>|3G /`U~=7 ݳ3ӰIn@IzOHٮ.8tJ Atc0 dje#F`lKN@RHC[[qvm/a֬Y@cc#gy&:`$D#fP^k>_{ϯ6VpHC0-δ"|!:@D2-Qnvgh`GL:2B`ZB,9h<$ ȑ#ٷo_IHJB!>;w.wqvZu]ku],[n!# klOW^Mt, 8)~8H0+3!(D(#& eY_EPD $wh  AeZAiXL?I(j܂hߒe믳nZ͛$ITUU}aÃIHJ8pXME83j ­{HSCƎyG34?4OwP~?GAo?0h,YDBEFEV$"EaSOQqp<(9DX  _D"jPpdTjM\O_0Â6x<#vm9r$$O\Չ:675qϝwq9iCMMtjbhO$(Sg)⋃8BSxCa>X[n 1c444PZZAD{nvmf7QF~8l^O9l;ǖ/'EQa^=ħ^ΏF@FMlkmeɶn +PV_S\aI<aC-a/k 0P"4C 3!P*{};wjk)Ƒ?#ܞ:iIC4¨M4640o pP\\~|&9tL0;v |dE9vy@:ٳ+bq8|n}lߨGvZNMinvi {?W^0$% _a:u*iii׳xOƍ{:f͚Ŋ4xy#קh{eI,0s&Ofxz5U 㮵tu׬iJ2=g9b8=}8L#|#q?0/S'M[9'/i~8^fz F#W55nGk$^ QSH#ݥ2]dg[%9BCDUFRl6dIH:#6"ê+͵+ E|i噙 ==͛x__?B(i奼t0R\L0}AP"\k]^.ɰqxRASE.Qy}+\1|0bj +U2.bo4e@r~U^>lcMT~ $1YLӀZ" kOv;$wMGĉ~2_}IMM媫`֭呕˾-[(3BzD{V^{#r3EFev1wuBT0 wwc# =N~y7/} C?)J^~b_sϟ)Oa6(%s8OwGTuu|Wc9 qnyI|~RDE%fE1ev7RL0lIqrВQAZZZ1Wƌ&++ χGْ͂ȱcc^L^1aԐ Q\3v19%#C,NcMZNĭj KSXn)daWT4Cd_y2/|;FF~"*THEƧmHٝ8[ w[II__ӟ̪U>_ŏCZ~χ  Z\҉'fB*7n,]zf}^r 8ԨfFrE9HI>/PQUx/_4YVy@H-SݑU{tF"禋$ h *@,VU.0U.NY/RG$^4E$RO'ŐF0g}6֭SO# aenڪoĶS&&u7OJi^IF^^O4"aS^?E4Ǒ}#a*pl)\x2Шן[K_oTiyGPoD?LWR$#Ԉk]tTYfZ8ʼx3?[{+\>_@Huu5#G䣏>Loܜ1Z_4e$EX;eg9cUQ]o0sYPȌ`zyXO/( .Q0fCYTo \.:*nQS- D@~u|ke"]Q"SLPJ5npCX_z.A} w%q&?&q+p|!܀A8>U:a'j6M9U1yfKԒGT*23xkVFX~C_aWU-Zb$(f <a[ CI.Q~< 87M[,f\~!/9'Ū n1-#=F꫿jW8Y8?,']|NZJGǒV"x;:'8/TMr8z(OZE Uˈ3Ɔxc}}\Y^]p?u?~շ,K+*Sҽ V/Qr+D(*6b%2KZ_'+zl OQ"[!$l2Un'}!|.+gvJ>hXjBYfU{,^1cĮ֖$9(}بM(}"O y]1ױ_US~HK{[_ c$&ANLgzz TPrhn_Beˌ>(`T02U/UBgt@ ,\Y!BXw䖹0DLL[87Gݶ^^_[U W~?=K.KlwJpk^z{p{P-o(==L^M]}=MML^|]]ܳG׷IG0H$"㧯k@)nUSqo+ >8NoF=&_#)WW.peH f&0OvGWckO o$C&])UNuG({K`Hk殺b6dYflv/c]Bp9jw&M]ȓtbe-ۮ La ̶W)~zOaz:N؀}Yٜ?i"`d SrHZ @ ;wrݨZܲ3 ɱw*|>6QTp\ [u\O,+ʯ%7p$ vQ7g߁-. xIKՄ,:n@Ek 2.oǺ6eE@=[Y6yNY)$TZop݃TO@RNgqՕlذ[{>\4YblPDU(O^@`?F'O.Z017#V#*I:(NQ"p`44L;#hjŀFRKwcǠ7~?ʐ}@ jZPnYP GD ,sϑFet-eN\4wt2g&O B-ݼ ̘1.I_'sIϙC̐ +kOSzi]Dzp,P 0W#Ǿ2 0-";dŠJ#e?) lﬢ7428z;JDU~J>v;EnC23lv\)n^yGkEb-Dذz5۶l;@sWWl OIhi]񑨙 Svp'v6i1qnGBQV}ko?jv{Pa~o]u/ MM wEx'b,8R9R:Jv҂l@`mR 3l6jxc.r23IIK G?⽕+y~Wg(,,7dȐ!I*ÇY|9---YN's c׋WIC*Pa.ΪhljsyZ+џJ7541i^?S] FᲱ奾(iBUhT&p_^|o`. iרi"!?1{EUy3Q芰a PW[;8 }Ȩb\4u Ϙέbs9 #H̾{{eY榛nbΜ9\yI----RUUU6*NPbGsoԤr8Y m)i y==ZKp Z{{G"Ѩ0 %78+ ,'YUvT*g 0;4'yC䈰ڧrq]4|t-BRx3W\7?|%lTțȷm(Un̖cVYS&xW]^E`[īX_[l..)-bze%SfLj;fjm&&@NDػoN3٪,TWW;vA7oߟo`ҥ=zO?@c6|`&vYFYUx (l=|#mm,7.^ʺ:.)&튑yH/tyOoo/t`Gic|n'g{b}u.Y ŲVy;c>vÇTFm41s!(y[fʽQj"uDPP9-U(OQy7iidm G\6($XqTTTpС >|Tݓ6N6g̚ŌSU_Fn$?dtd=t|lZ +*t??`+z>#/ "EôLFduWa- OqN]# AR`DZCBӬ<*;ߡOPC`_/u6QNIX!V'T! &jo˜4Ubez[[e<<$[[vmw`d~sʬO׶`XcO?v}@ իWWw^x.$yʸq9r$^%K_O\.x\EJf9w.7m⺥Kyᕗ6\qzl]{4W{7m$B( Ev:a0V#ah{K]r}ʾPCA%ʔL`EWǼ^h@4/"Rg⍳.ϿșW^žݻYs'۩˿sE˲m\`Gd^5Z-nα* *PWEKŔ(Q Aݾ -.$Á=#O;o'73<:up:HƁAFFƀsrr룡  |!cΞ6]3~3GJo|n]ѹ9l8taFgg#E$.RŽnJ c-Ĵ4"~;(NKpqΙ9tQ8w[ 9= ?R0WxY0]w-.͔y+¯\R|ȕEK.b(e%u)rHS Ps'?UN6⽣]9gL9g3NIYM;6p8XW<@YEW_}}>ߠBYl~d,/,ZDg{;F#=|]=snc)Z`9~spaXBA#Dp 4 jG!MSUGZ,V=A^6Yv?k!wXK/1gPvA֭;h{~xy|P#$(2!`gҤx_߶)Nh  4'25)n:m s;DnUྦVINFfS#2{9BDdXM-eCj+á^zs/a*'G,ZZH B<x<?8.D - -) U@c]{bkÖfuGgUrl̠btVss]y(O]/"(*cÏCUY 2ye g )/Ӣ iLT新  i9Q TAU{ђ#kEYH\g;ɰA6p|[7w6wqKpdQW/99náos3O(j=48( ---zꩴ~>I V gڵ̝;s?/ڵk[nadffrbfG.lYCVR/Ky孷p&=f5Yzc_cjO3k -\*+͚f~e;v (TzRh뎄 NK;m ?ټ3s4{/-[xRfNa7F\njW.i$&qJZ {}Di4TD%F%ڂ!n'(WhV@D]?+~Dmu lbG;5YY|D8]PBMq{RuHw %/WsE~#'hXfn7OTVV2aVZ5\w+IKK{ƍ\|*>񙙼ET0;i)Dyu}>e?OQPZrh+%'cY~ewp*2e{8xR5OMӔ2 v%UU|)ڪ/J/f rnS= ,ZE]䮻re1jԨg\s =gu999֦16FM\νiK,;l᝘ovk>x~RrJvbsG';nׇ\B;vh/=)FZ_EYefq\"(|"R]T@E~>4Fzqݔs0pJVөA innf/~% cƌaǎ_n!H$3<î]kNҬCY:Y6лvRQE'bUq~#O?2 ^Ca4{޵_(^/^jjEEҳrfglv v-(˦LKܭ[neK6`bbsXd O>$?OWYȰ!9%⑿=3]SúkX}9yxRRVyI3io& NN;fO>9?x $|E x \x'Hɯ;rCGsg ⥕0X|u~tE ! Bz]{(YaJACST-mx~<69~2ߩ{qո֮U8}/=ÍENg~~0~ -eNQYY'!C>F$t:7I_) E,*yWl,py䧧Gafnk%>~6G6o 6@|h'ok?^s5 ;~ܪjc"gq>(v=VBGG555/ w܁f\wu󤧧1b)XX'da~m.cLZ۶BAFF\64cv|ߛ0WPcgQhw7?!s5yaDN6D"~T^ڵ\7Ƿ_z)H+Ө-(Hu9cH5v;Ǽ `eq0,; 1z޷pΘ,ɉFߝ#pt޳e9,& xxȭG >nf_{'LE M2_`6nH4/p8eĉlذ?n>WWUq套eZxXh~!sOWK36˙6|8t573cH8'6r+v H[6o#R`Q>/;o&0?_1m.Nqc2ax5C"󇏠roۉ/`JA>{d12ƺV>v3;ejyl[dƁ hm⢞cںzLN5]1@妤z8[#p^U y`=0 .^~ s_V(X)'===s=L:_|fĈ_:@ZZW\q+W+FnW >m'ڶ~S2l *2xszFdzuEeaFWTχʼn>Rg^\Ȩ<9Cf1>'+G} l?|Sgpó?1M?lxUWs= Y#2$/t^?tQ~:]o fLYO53|j~ne1<Mbd n}m2UҀϧ5v8bx?|R2  taAX~=%%%~)+1GX*b2q14PPB![K籗^btabU99lڿT {$ `3J9pG>D,q˄dFX:tOwơ#2`(D,S񰡡a).ݟV yadtqi_pƱZ8!y^;4Caڻw4=R96owgL 9-^񍮹v;QQWR]^/t~up@ж3CrFM͢Q3wzjT232d⬳" 2{/$'ؗQ)+_Yh^#.r *+9oxdQ+1mm];ONass3UQrQسBEUg֒ykVaLM-"DֽMG HmfKi߷Z#G(dxA>O*e/k`dnk[ۘUR3S&dm!~EGϛKso/(Fv8uN)h(DX$I/uJnݮzşncP5#p?0u,^DQ䦛n";;{Ph׮]7k{{{0cƌ/-OD7~d7d6XvY4=Jqf&N^XOoɸ<BMV&x;s8;vqfq!X`cHٙzpqYܽk(rQq!ms҇]=Gmu5ƣff1{P0h}}L--hWzz]Zu%l8r54'jJGtwlMq5ٴ 66o,vK.ѸQ4dN߸iӦJ˰$탌.*.g? _`|̓xPG )//|%n$Gڛ ?7bp,*JKxIj~?# $Ħ-ܽchOsgqYėT~6~,}^MHeq0V>EAfsW7;vN*pye%q6xƎm)yZZ®fUVPUZjղM-0=EzNM==$7-,;32Ěܒ.6f7- Eqǽ[< D8F":::83PU5"ǎ|WHG"ݧŵ^o͍7zdgg3jԨ/Ux/ F"޽ot.Xp6WYS{ၽQ=ݹiC*8DkG'xT7n⒚6 NS}+ *+5dյt-/\=uXP5 \nN53$ҼK/|iƷxBȨd^yn*؁a7Gp['q1` ^a^0 J!ÇZRĸ ;rHG_$LHW3OffMַbBW;ϝ.޹@΃GbdM|~&fAYGYY3ӓo$¢"&WU̖m\9oI fdp9؄lSVQAFz6aEǡnRRI"#345`/p^zzzGe)++?̛r=x^~e~ӟr%g3GΘ;|4k]x,p[?%mpۑ!֎vax4 pߎ]lo$'>={uxc y%DH0^ucp,Iƈ1vkPn:OѦo.;g1_wGc{7ᠠY&OcW,cw8HfwV}UUQ^0===aTU%55IeeJ@OOR[[ҥK;Xpa|֖5/ fQ20M~K?kOƵL@s3e,YK80.'- fn#h  q N}C6KXh!YL1sSyDA@v:rx5/9#k4o#ѨW H``A^|}&aCŚB]K Uee|e+ߖ$4`s:qy1H4J}}}$)s8vDQD"0`i'IFnn.nQy8pw'NL]͛9sb ;w.;vDxvr8M\BzzD"t470w8 (*W0tp"p>R{:fTNpѨ|93o^b}COQZ*ߘ1]kn:'7oa¨Qڱ %}X(IZF}8\.liZՈwj~KrvfƌgM,<眓nn~SSSã>zvoI2} YfGSSw}7\~q?H˂^MV-m@gCsr47_ + nJg8~:g6OI?@'|F ,1ݬ-.kz/QE Y{ ;+$mv=w_ԇxg,X݇lyWhmmeҥ$$//|% ==nG{{;l۶m XrCdzRεA~n6OQeblȒ#st3%;ӆjcǘǖV;;'˄w2#`s5PtrJ~TiF{IF.G^|eܿy /8Ȥr)Qmgt,EиUl}oIcOc83Tf-}yP###~a~9^z%.]z¿(tww$k+F9st\)((p8?L ܼ3 :ZŞfÙ2IW4|T{Z-UCyp.FQl:t楎nf ? orj&O4[m" :&nLzYƬQX޵ΛKqzǎeJƠLV<,z%]fvx7  Y{---]2/_=s¿{便 ~%oeʕ=zQYbgyl6))cl$jZV?6ϒ4?6SUc)mzhk篻!~&s fnE<:y<;%OS|1_?v [l/l8sp#@Z+ ( "EŜ3k&?ZcXESM׮擬E7HIIaذa>|G;6F=޽kǸ\p[I:@VV===: yW8w^/vA`Q"@ M("+- a`z.> ,kng/ 9̜} L?43s믳du~̽8Js<$k +D ,u9pO'53db.Z|.X=Dn~>o[O~yC0K=.p饗|شrƍ/ku/x1cpr3a„F(*("Ͼ*YÝyse.r:שG-Y 92rmL--aT} 0'8ttu ߏf\u*60k8VG˼iS2i˥}+Wtyfnُh@nn.sW^aٲe_S^W_׿5N6%w{ZޏO Mkbu73r|p( rE"?ƼbU(%(bԩX};<7TqgRq%,9f7 ƍu8ǸwF3tox7@4KM傩2C~@ee%?j?J22gN'ZZ5b i :bև hu<5'ಮ^<K31"999SO7Р`AHOKg~ʯ(47ߤ<+W9sAlaTE ۖ\^3zpTKy<<^y*׬atxWGa'q8}C.dEno?Tde6T};]Z[NK';'(RUTDy^m>/I #{雷iE"`D>( v+G!QnA;'D4Jui456p>[F-|n}\:~OmKj3 |^MEьht$ŸloF~;e:nZR2SRt[DVþ~6o̴iNح7)(jJF_S˫oДϰBApt͗{ )(W,}:/@$ᝣ|s^:p+VxV.wwQ[YɐFrS?|ܵHgg1p9ttr属O}L$(\6>@?:z ݺ,6eWmm-O9Դ4,Xڭ8m.'2S8i/yfn6mk1o}݇n+ # gfFL)iaNQ<"K"sͬ:@͢s{G9c|&ONd|HQZ㫇3 hcURTĿ.8fS$ +с(ȲySOe]uQ,k!2m ;|"a.8o1n#'1&hQ'J'㱟x .h>NGGGR"%ߚ⫓}~tuD|~dIԧ-="fq{dn<W[X;@4º :ؽ{7c]\%L^J LnZ}"t̨^cׇeM;KI6EsfnĬKI֮LޱLu8LS pņ~AkAVP(=͛ǪU|tYxqR{pr7 -|t7x)ӭO<.'|oO70[ZLw j d2nDG^x6>J1t(]>U(1]Bj栎@0Տ=?Yf쑵v\ֲNsl=/gz-R|q{y7馛~@X0i~["555=I89q88vE~~~Lgʕ7t͛e2\H0Dvz}}}T1c8?1aP~=r̦M9g"}Yه+Y"rA8[aen:u9Yz>^>C7ݨHlxGjfeho4ݔ$霻hQ raqN!>Y%\Biii2\_233co?)N 7bEg΢9sb|{.|q|kG0v0|ݽiCpmE":2;6m#hmh`dJ po$Bt_RB[mmѻ8|m--\1m*Nѣca# Y.l(s(dB8oVHg2oJJoP|k8F2hlzo[s3<,qy4E/[ey)H玷ΊL`_NLvj*_6e3=tǰpHY1.i-f,O*EYYZ[o/1!6LkjyII-hD٣&8ZH8;k6rqfO^~HTI{l^ Ǎ[>?UÈBFXM;S<{YTǍ幏7!l̜4IS,y-濱/]OP'^ٱG_bI2kXλ1z#ӍBgMqSHsWgp[fϴJlMuq=y֡Jw. ee! +H/[OYGQ?\Գ՘e?3=Ұo&TK%V-XzY[vUyۣo`x23(+쯕﾿nŋ)(I?-#M/sUWiL0,4d0w{;vpUW[o+>]?v{Ig쳹3_!@~j*,bE (bKpl^>Z'saf|w{^>Qҧ?4zK2.PǍXK o´yW5kd;g͙~HjN.H6c-Zä$jDC!_HOh=K.;<ʫTr7nbڔS̕X[hyGrrv(˔auGf_Kƌg`rY+ϧ4?߬GikECӉ",3w줴}@33IIqƍ923nNJ5k᪫/)a%Kc¤I;wNWUzz3Ӧ~WK>a`)G^& +/7EѾ$j52BJxfTq#S QdŶm. !jY,X[XGLKtLU{"3nj)CxUTs…63LєU$qЪXn0ݠ`!#F0hL'\+|5EOo@7%kK/EDa Χy4M}1vٳx,LR1'= %%o(oT{92^Khi֙`REW_}H -<M9tAq~6|̐!zŜȣ({R8|s'㊋-Jo?@adp-2'Y9 ezI'/"\ae|M/\ׂٔ@@$B bG]7^p;o&丝N}4473Pw P(DVt /+=m=K=0n40HgGW1e 3OϚC8_~Ρ]p};' Y2q8xj-]O6oɓxhGXeKf Z~|]?FKSfE$a8cke0hIOʗ !jj^;+1tpKظk_pg["C5WzCx\|tMF=o7h. I;WThVZÁ)n-=׈$%)_:P,E &Oe@/:T'i,_R5=itRSSgֆN:,B&=l0o$y%~|7!Av:KK3cU~Ͽ@CK W_y%4EKu_Oʗ+}ܷւ`ü3] 5ђP}F(К5ݼo?+[1g{)9ZQ!-=]69T*%LMIaÞ= --Lm[Œo.'7|̡zF ˗smiQ ct5|H@k:ʦ JoVA"# ׅii`/7m\ejj{yb*|AEnk]SO5NxGؽ{7w}7;7)~qPpcUe;mjM]쓐2ƍeo0S0u*m1<՝B8A~Flꏽ@tjC"ii$5/bMXHCQc3ss(>Dgۀ=9-%9~_6sDQdْ 23ʲvmQU+c֜$r$+V_gF^=֭Xh4(@CQZ'ogڥ1&1'w3^a3zR|ْkM$EBwFnF˓wfR)_Xԁ`QUxUR+*cUӧ#Y};KTI^giEFb\=I/MXkb}b|{n#P|}omn&M7D4MNWbVZa`qPbOk_"D 2UVj$a(LHQXbi\q݁, /q&˹꫑$)IrX|#0L @Mp !q`XqύwYΘN}f~%ëZ}wMMk$''r„^5krWg^oNL׀0ނEUkuHX +~ .o_ں|IpCoE;v1ryK{X;!7fzWCqg5pD $  eg[ Pͦ~زً[h>n:tsnjH2u<#;\x3" K7bb ~dބ^F7MLD}Kƫ"=5L1ez+6;}q﷊ߙݽgJ/ DH1TPm(KҪ 'B+(JJIB"J H(%!8Pm;}؝@Z]ߝٽ̜=̙s[z5&.\ˇcys3^Nxc |7Bcmv q atxGv@ 6u*T,Ǡp}2H+XˁǹsFe,fW.|5w`{ 8t$RѹsQYWol g}- =lݱ':>**ԫ'U[( 8~---qA!ގp4 21$׏\m-͚iӧUKGA.^3h?KuSgiNC+=N~BQ'M–͛ !W)] lzl Cؿ+Y;={05Z6^ 9..^ñ/΢f™K8Zf@UUWa.Ys/Ϯ_o6*Bq ?'`\^}N(~5ob oG'̙<A`E t"~n;;1MFJ}MB>~DCWշ'?v GO~)I`kZǵw۱q4??YGϝS+V DK֢V`]ԂvVUL &ף{$C|K}>]mH{x +@qxx)HZ5ɣZ8ٷtt`ErGԧ":.ڋnT_!r<^u66B~J/-XWyhs4j^<ӧf(i #@yCC@E^޹z=]aׁ8CPgQ*Qe3Ow|uܧqOv ct]m۠MEƘPwGa`@y@%r2 @Ow7|}aNbMM+55xb*?*\Gmc#pc 6Yq o@d4s&":krDjD:W&u>LOO#W’ŋĚ5X3{63Ϯ^//]Sh`?_@KS{zP;~|lheq[KNN+S\|96nDF jD HŎ5!Oo'kC]=:Ϝj̜6l!޽xfcXڊc|\g?ӫV72w{ReF`ܲPj@# ^l}q8kxaժdA~6mX`AR~|[Zzc ~&vΗe2&>L/k2TU~kSx x;!b:)>NCaV`&=GF/I;4\B2KkaR[J '}T4)D쉚ݎkgIK7߶!&PЪw2 z?H kAPM!Ju>hb}}}صk1o<`2@VLK D+W ̖42O88s+~O۷cʔ)x71aL8fϑ'JräFdj D ݅=;9F_WWӧOCJLȘ6Uȷ &f.%i$-$7@Ŧ(s[ԩSQWWLʢFФj|a0`JIs`:y޽+/sM?Vprg#$@>?X>< ֱ\^P~m/.+;vo`K{&KN`iӰAL>I! ;q?@SSw&v!9@5>B!/YZ6V0GRX9tQKQ%W3L_T?5TyCKR7ɗna1԰WjGWfgB;B1oDawOx.xkwF.NodٛTZ B!2J(q:Rǒl$=8l'eW)y県sپ\z{0^;e; N@ˣn/RPYJoo;pTf3rN뎱"{vOlg2Np+> sRJ!<D9̴!Rڙ+БR= @W(=HԓKR𤄂'qPPB@E ( 0˧|U#\ֽitϖ8]~V@JqL~uϻ,2vhfJ)~%ܥ H!B@ PB(! B!B@ PB(! B!B@ PB(! B!B@ PB(! BM2w CIENDB`mldemos-0.4.3/MLDemos/icons/new.png000066400000000000000000000402271172143270300170750ustar00rootroot00000000000000PNG  IHDR\rf IDATxi%ɕȼ[UuWW/n&9 3FeÆ2_H`؆dx aCۀ X`XaH&hf(9\nMZU]ۗdv"2Wͮ[p+|}ĉH2@ ,&]@A@ X` `! ,0D@"C@ X` `! ,0DFW5/uO~c/U >? Om.Տ~| NF?Ԧ 1/W$MS!a2SRɓԎOy?|S_a';miC԰Nݬ數%sv_+MR}ji(Oy5u-(E4IǛoo[>cº%l&K폻m9}YMar 脫;f7x(, Xq~RC]ʏiDr=5==I!'~(Iސ1.^P* u "wNVPN{B:KPD|s7d^x2IPmw얊WJBeBBKL&>]{h<)8n*km7poOA&9oޟOXTN~}G`؄sz( `u9Ež!M΋H?ԉyHI"0P>/ eps`aI9cd~vژ?_IILJ:5p_n]{>}xcjk7ocs{׊3RJƼpr2rVV6>\@kȆfi֘[ ,(&w`\GcF&Ln<~19.[[761^NwPV ^`d/8Vy̒&MY&Bԅ#\^xxzDNv2"f%x$LE @0'u%6aG'mɗ[\ t?V`TyZ8k.~[x_i//.N'&p4N8y1j;I" GÓRPUt}\6iQr4 h< $V+h&"?0kmǘ'[\_Ήeqs`ʚogDfn#ȟ-zHԽ5oͮ)6W@?rkSkP&Vs3)dIȖx(k6.7 1z.1zv_Sy>=/;kp V7m$) nx=B?s? #cID"/`u .$i a8KrΛ&L< LkRNw끴c{whvNk8ppt~Q69v=!&>'贺ҿ'?OJdԪ `(iC- d-Z-E0A50D=}"vȟ e4#|h/RzBx^Ogϭ ҧΉ. i'uve#n'@ u :=C5pk,wL]'2]y\T1xxn8`b*]e[sWFUo9n߱(K,/-lm[Z(ݫ>_a8ooA ZVFhJ@^Hd p`AbC<ZczwԛVɟ1'Yk2&!B)QE)1_*QWo.0ɽ-&!e'FfϑbEG1J3˸b9S",6XF2D6} !yHxw rk=@-+[98@duj ,ҀWʒ`LA!i%׮ ?|0T1,x{m,zx'˃.2(<uT.vp8 o޸VB0C_{VhxyO#,u8@5(&@@SܚPs !HAt@= @`APP|$`~ͻ\2s GӮH@-ORW,3ŮY1X]NIKD֭|#O'uO) p~Z}9<m܋]Phskƌ`av1M\=ǧ>wb~SU_R!@3 vv9$pppfM i\*\לּ9߷GS韵S^Lg^bF=gCܸvZ)tV/6SMO5h ]Y:bڳ=gM{oeNn$2+@"C@ X` `! ,0<`ooou- tҿJZqg)3o~ze<`o)0f }nzZjvBeQ?|vvu,~ÿ^w~xߏ p~ܺ#QPH<>b? (F >D[j1X3@C3 DD (>+Eڽ?߷y2pmv(d!A@00&|15'f{m|{O F>sf,/$ 0&pAp#D^(\ I#Of}X|V  'U   A` } (,^\ oYwjX q^#  =>``!i_@cp MQoy0'.UĸɍlQ'+H @0_i}o~ i171G&x`C۟[~ 49i;];f@@0 }ޯLpHtNm f@`ɟ3s7š`n=rB=%Goq;7,xH.<+7X>#*JBfC3!= xYxi{mw g1Mf@I#F(0G" `6A`tu嶚dS|# ",-:h:E罽"FY^1}ޭ~ R> sрRw;R psޘn6,gthCI@XSM%l_2u)x%Ô6-PBAArw>'rA>\4~' Շ'$(M` ?nv`1$|$U*l?+{0gT5E?woYk"ھ}x'ϝB|tm'EmB`x=5FV~q]}z&Zφ&! Txx*:'_8sc4bI8ɭCm,?_g)V^}_ĹshC> 2x|29زc Ф7D-` ZdM Fn杛#ہ> ?^`9 k_*NCsC<<w }RX̓ ɭwe5j{y>5C^ƕQ-=]<1E/hW< ,Vp5 iwp<9›w^G*65{m|:1fnbK#S;Օ݉nO(K|MɟVbsppsx~mn oolr4]aFqbGKxkMTU9TFk yXU#z]$%60Z؂ /jq`/_ ױ7K<}$xVTtWT}sdKi\U&CTRxpth/TiRTo+e)RPT@e@lo@vzTL(Rm\hT\RkT L0pp%e݀pC} ;m/]K/N I7v;eHx Ì6ᰱ#&=k unn_CzuxNH,_()iR§uTqnDeHEm8N5[ (K!'Gh-,wVZFձ޴P' ^LI<Pʨ$|ĺŘ!*oIDyPF h *$?*TPn6XgJu= JI=&H_g1&Hܷ<)c Q.v 0M `˪@YZk?%;;Xj/c,[(u]A-r`Y矘3cEHvms`O:*Z*?3ƍo@[y;im79>ǃܥ aJ +WC<9qTN&'Pr|qvm*zboNjg Zeɯ @m%¶<u_/l6!0bNY7*]/kX_1hR9I<&wZ. n[q5-ܾe-5@;X76QP&Je.Qh'UQ5quVƠ5Zgm(*x(H.$WGp?JkTNDLOaĝ91z(O`(Ddy+,"qClX,l9%窥o*eyX_Wc m^í; XPr P+Na4UkҔ8^eWc=H?CrkKepP{F j~ۓ{u4t k@`\<ӫFd_SMN j?`2h`biiv*4?\o;qdOr/`&Ќq JVU\OS<&.[6h.ۮ͊)ʍ "`2,z>p @ŖNW+K~~O| '[[oËMB|2N~MP"o3{h m '0vlmcZ$`eO1;fr th9o Ā'?p2|l@W-_9sAfb q4<N̲F1t['ab.( D 0='pw^ E.fŹ} =6V0iaP,aP.ZA{M(yy' Hυ6W!vs\~%R++G8Ktʼn5Z~CVaCcfNy%Y`_e^!׊3;B:[Զnv^qRU{/ GQ~]kdEK2: hm t~dqL`=`5BW-1*%xJ~0?,J({ D,ә-?x KQLPQSv/"uS >(U K2Tt|}= pKTl@Sf*N~ML 0߼S~v~'šM&%v|3:pqbw$Ն rS|P  Ho̱'~QĮ?"J+0 q/: T#շ.<0Xcǘ']ٻ'~n[40`3l_x[{.~;OX0GD !VO”4v'8=󞄽. b7wN> .bמּÒ+*(W6 )Ӽg̀d<~[z iC7$!c ;?!#5 )0»ׯrIH~^r^cOinaP Wt @ @cNL^CE$?mcx3bv{X}n4FA0/=#>\lϒE^BŔC`Α`"]jWzo8Gagm Ȩ@iMd`eBgb?'XSI() "yLxb<@P.Ha_kG4@ALȯGKyCjj4c+ZUb)lj$|7+Ff#s5% _~D PPq۔(~n[@.~ xf7e,  %?bv7500&h&S̖;TJN{qkUm.qGo@bbE}{Bߑ*w}#{;@\~6"ӝ٩мQL˟5e~naЏV]0ҋ='VHgzCxp U|ޒ^/a]i*9:v+U`ZcdF8ԇ0ƠX*/WU3q/8'IQ"m(^jo6&:!ބ;JG>@8HpẅfiX ]rVe]?K /_2jĪZJi&6/߻d/9c36V!ATObk6g p/Iȿ[zk<0" ,4B (njmZL} @I(Z%ʢe1 7a ~6X_e=Ia8ϤKc4X_^Ch4 eC`A\^Z*v t _q_Qwx>X.yvr<^ W<>!nη.S]1X i zK(T+" |ϛ$t/B{"_wiʅGp{w {{?9zݮkKTZ;, )80ki-<8D .}{?ކfE^gPpg- z ֭WPXP?>XLJ}8-])vKŏdO׍#?úށ 1 )p|`yWÓX!y8ٓ)}sHԳ]cWPR OG6X9B$?>-X*_C qzW+ :< 'w0V)KO#zC^A;F6 1| qFO)0Yh$?C1!_( - ưڌ{sf?ֲ쌷o ѿ628Q;X*7Т~ .J|#ky0`}"`ۓ0(2~_b,x\.Ͽi?Mm<8}]YϧPM䧂ۋJ)1 L6ZC@_>" -3C.Lmz0p>=}>lW.F!@ܣhfѳ}Ԕ ݶoB[m[|vZes˭7qWש B߯E(Pzb Gx1 [*oG-L>o?? ;FXE\^3O;[16pw`|)/*66.bw7ʫ?0dkzRq5rač@B\l;x籺~h>yr(X}XaBv66o'srxNw}QyHH?+R{[ū'>G/,έx4O_}wrIh|C~*d=轲gc>>/|]FO\7AEW?G5 :x8ߨR{)_Fg$g5oxy:?W5ly&A|O&m/ɇ 8Z;4.nmپq+88~0?H2C6(71l=禪2z^2d[z8-AT ׮_%|_H{<:F?Y^4> ) 7@YШ޾sG[xo}~䬦άɗhk^81(py ze< fqVChZNnD~/ȗ:nAI%Q^{5`ZE.cg ?UxG/}as&nLqרp?eXf@"?~;u_FC}jpWg0 `8@XmSf'.NgiF[hinIh4HO@G#Z3<Շӻ .iLfcME}G4^z[߶6ZqۍbQUw/ pwek&>E!'yýfzQ~ Ml@ D8;"0sl ~VO ?"D&9pپӷ4y9 TY;7q`Awyg2hvHx<*wiP+liyY,`ȂWHdE6~Xx4 \L, #n_~^zMOMYQiw i `؝D\4Ӭ}ӺAω1O|[\hSDן$"FC7\m1L! )@p'8L#ni}AX]{f<d&>w>31>a\kLuz\C^4 D z)ÿ08\<5ܺ?9U^&MǴ0ZsA uf|Nc:]OHzZ[{#%]y>d5Mg܃kc~][tbny`&nz sˍS,|B3'o<~HP00`^T/;w% JC)ZkQXVZk~hF'G}L!C<lBv73mɈ70/@ 2ˏU @<l"o* 7fLI[|@hcōJ,T9W1l/ ֋U ʶFK  P @PŔBr:=Ph6 *"}g.ll`Gxd|kW6bp0TY`w >r pKo mw@;(-cFxxk qGA`6~oO|x7zMTzl-rlmpt`m'vV kCOɇ'ؼtïpt(@pa|O>y |7q[TdxCK~>o2 U(Bnx;w~G'GewӄU߹M'lO=*Sa4j~2[K; ^+g|uOqxl(N魲_4m ">C>.ۡj2_.~tGXOlUxnIFIDAT^{2j@H@"C@ X` `! ,0D@$iI IENDB`mldemos-0.4.3/MLDemos/icons/obstacle.png000066400000000000000000000061111172143270300200720ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FtIDATx엿JA3 >@ +C+ +A V>J+AfN۽x, 9vݙMD6 -#`Hn&,MDYsp+kTp`3ǟV |"/\?UW4  l =M X pz\I$2qEXm57v+WT@Op;p:peu5yπ]߫>T2F݋6U࢕w3է M~o0}~ ~*4edS2}o= u H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATx]TeU̐P4LKԋ¤ I%"3o" .*CJ054$K#2Lw]w8Ϝ9{sy9yyϑm$ыM fD[ryO"\%I G%Aܐ)qx5@VB b 1Qe%Ad{"x#A*䍬7D`h/dzpHIm8uTol_YjBVKSE d^G`9Ds|EN/qg1Ry ,_W[8D-cM[L B`SB,}0C >ɪ]^z4Ę r% 08282mAn*;?FYkݎbB=6k? FW[l(9Ic^%-#!a+M{^dXH۾>7HZcǯXN3+Mop8~4]12J  ,=,kຠCmߕܘAQҝDKJKNv,=5u;mwf{4P{ W6G4 ıDO'$b2UЬGQqT,U `#bMKҮҋcVԉ׮F\,=|+%2X^"]Z]i}IENDB`mldemos-0.4.3/MLDemos/icons/regress.png000066400000000000000000000500431172143270300177530ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FENIDATxy\U?3we.+ieeK%5ͥꩧ2{~OiY2KLAAA\P@\dg~fe_9gf||9˲ }<@ @ "@ @ "@ @ "@ @ z+b_w4;\{L|=)bX#yDʾI5\, &Pk 4fkg…X2_W7ɚb}KYw,+X 㹙}JE( ? ZSŒϠ*-Nr"ŷU[Kd9eL,^;Z…Sm}(=ɤ4}G,wT76Ɵs8ύƲ<9dp/y,\,c}c9e?7 ,(,l,Lci k>x=^q]+13g,0gl.e5%0oL2GR͟29Ww,w 1PE5I .0:hSTˤg[A\ ^/x>!j~ n+!&BBA&Cg`k x| Z 4T5H$bHɤr{64 qd8m~3Z0tp/!gxfX#heev~4oa-e-%kf< ,6hA8a65s/Ρ(֌/e>Rf@ EA %Z@)AGѦ$4k- WgqzC I[h\NzU=jY9x Nvo W6) ڦV^旋5֘gl-H(Ψx/ע7=Iڄa 55qVW 0R,{&π#k2kj&-dKF ʂäEZ`v PWӖDXB/@0H~l>.gC<2 <YZ3π<3@в=[ T߬o;AShuV֫T1;_&A A0ImQXV❫343mS:}sk <o[8VôfxkF7 y i&lrC @󽲂 Cj ֒{Ϛc[wO@{LZov( _0LL1[hZ Ups((ՐI8z]ra0\2o|OlzCXA+1Tc G _46n9%p]ƺ(eЌTLb#2Ls(aץ~Q}xJf7*NםjA΄)xf-   @r-.e,F6/Ȭ7R_%-(@㵘!n;rL%PQ4M Eu H^0pՍ, )0, w3 j WAI%hє2zϭDB3f#hΗgǏο Tg蚗2)dRկPGqqB(뮘V帶5׊au8R1.Zc񌟲RLZh@G8KȪB@@  D@@ ܩXpMܸQe]@ S؞<kʤ(J(*e5|\p]Rh8ڊk<)kks|ߚ1vq5oj['|NyVI[ʁ]/n ӗD XgP⎵beխou:Y؞z?s;PNgRQxړcey{-bgg= 3=DUUrrr0j( eee#p } ^HD<iL&#@ 5Je?RTT "B_a0 \N@kA,w{ ],O@ :GD^Fii)d2b1QWWwwЋ(..Q[[ qQ"BV/C@@{N"B/aTVVBP pwwQЋ^^^=^/P\\ "B_4~77wxxxܒ@z2K(,,-q|x{{߲N7oR?pkzjz=Z-΍7Я_.+>***28::ɩ˺.U nYYY]zlٲ>}z%@ 0uuu`˂۶mC~0{vK@a.^.)> -Zԡ=.q[aժU.Ѓ#((ә+ vNC@!ʠj۩r>N?t ֩2__C=@VVlmm;ǹsw^+]y(A~~>F)ٵk^z.K"@ t3H$Pׯ_kv!Dnɓ0`@]ׯcXre@@&舠_PP?K.Eppp\#aǏ\.Lj#:TFQQmۆ%Ktz5zBRUU4bРA*|/^n^"B鐑J1}7nO}\[~"B'[bAQQQH$.3;;;vի;u @ tZ%%%(//R#ة>#ΝÞ={v C}}=ۥ8ǎßuӳ`ſ~:`ccxxxt{^Mjdgg^^^3f ryò,>444`o VLTUUp~[TUUa۶mSO=uOl!::KoD?>z=K̚5 QQQ$uuu8s lmm)W R { ֭@] @s\x)))Ann.._ÇwنCwpvvFqq1[̘1"rK, 'aYt钅4,_yyy|2$~zbشi;wÇӫXJ%ob„ ]jT*> -g^HJKKnY@={/^DHHFR &`ĉpb̘1 @ t7(,,Ĕ)SͲ,<۷x1~xhZz̚5 R7Ξ= H[G'0:h駟`0yݻlw^\E;ap1D"?K wƛoZ,X2^ӡ|n hZ?~܋/èFdd$6m% mݺ۶mFԩS1|"BOЀ'N`Caa!ǯq1$$$@*bڴix/_ŋC}~D-HJJ¨Q,̳clܸg}{bYJ'RSS燅 b/H:  11puu5^R?DMM vwa&q :ׯ[yDHMMń b\Yfa۶m0 ̙3] ==#Fz[D}*`„ .䄅 hܤS*eYoHMMŨQ+ty ӧO#22Ң3 cY?#.]WWWTVV"##[ݾ_MM jkkQYY NP(q$@-ɓ' gggw+>c(JbƍÎ;o"55666xj*(nּ<偢(b,ˢϟX,ưan zT*N<ѣGs[VVk׮oRRRNB~Ocʔ)ظq#~WpTnwu\~ #GhF*..FRRx˞-$jt:1dn?ĨQ0qD?SLslmmVm6>}JKK1x`7سgO%PVV'"""͖SNE~~>@ Xɓ $?74.˗5k"##o`رxo6JKK9?ģ>کz=Ξ=z{P,#::GL&C@@񻻻SN>n8lذ'N@ll,vڅŋsoiӦujIWرcpvvFtttrqTUU@:twk֬APP?P<]v!77*l޼FBFFYfuhPUU.]H'v!4Mc„ 8~8Om{ \v ՈSG iӦߡkRոx"0lذ.SNa„ DڃVEMM ,T* hT*X,T*'lll:,(--ŕ+W0}ywp  `޽6ޭ,# G{ 7P^^%Rp a888 4MR @RA@ܹs`Y2 >>>"bЋP*HKKCLLLño>9st+J\~UUUBLLL+#F@jj*."rj ^GEEp5( %Z'N@ddd͛7v?+Wvu j50lذ퓻@PڵkmFST*F'rbxyy zyyyHJJ3-&!!Cmqr T*߿AAA[V#??%%%H$G~nٳuuuHIIAaa!"""zؗAYYU[e?z=._( 3W#^#OEQ5[K]bѢE|7ƍ,#<S;ӦMap9ddd <<ΠA;CVV&Nh s̙3Q[[ k舘d2{x"ƶ2dU#!!9rss鉭[rǻddd`ԨQwʾE999>|x;6\pw4Gy7~/P* Bee%T*t:rssQ]] x0zh̙3}3m憘\~.\ Vݎ5˲8tV_`j*3 4ӧOGnn.1w\d2bbb­SGS[[ϣ>>>j<掉垝x xzzbݺuVm%K 55CEE-[vG=GLT.t1h /))3r9Z-#55#ƌl!22lz_&++ =222/Fxx8x ҥK EQЀHׯƎGy \vv6~iCP`??V^ /// <2 "'OOOrj@xx8~Gl۶ @dȴ8::"!!Ç'كMΝ;n:bR HLLSO=EHHjHMM5:t(lmm JapaYF0Q[[˵EEExuXRRu rߏUVaذaعs'._ '_sEEE OThZjDEEa„ ǡC@Q>޽@1N’%Kyf \p9994i.\ɓ'cy!88{JMMŁ H83&&HMMօ#z;DJJ N8{f/nPP[,_9s&Z-֯_5 T*$&&bذa߿?c='D]:M@T"11M[oATbXzuc̒eQ__ϝw^7̓^?{9bر(++Chh(<==~ir$''_~ܜqH_wƀ D">?x-tIKKCCCLbU<⋂[Knq̀g( >>>(//L[9) k7˖-k ]˛7orzѢEv >㎝1cfΜrDFF˖-믿sq/3˲踀`@rr2d2ú'N@rr __>[GBBBC-Lpn5~{vZamo8p z-^weѣG#883~{pq/d}}== Bau###?3֬Yf>˲8y${dގL&L&CEEE RSS,bcc-̄`w}999ؽ{7<<8q?裏 {bرcGפ둟Rh4ibZuuuj(--E}}=ooo.]migg^x?0.]?s㭷jM#44 QPP 3/7PXX+Wpcٺu+YfYWwM,qQ{'v >kOQd2Y_qq1"""₆TUU`0`Ȑ!8t+17_#G \mKʕ+ VAaPZZ7n ++ nnn8p`NNNؾ};j j=l0رcΝ?cĉFvv6Х˟w n"q%Z-K$%%_~xꩧO?puuŊ+ HcY͛8s bccBm J쌪NWi(EQVC4z!?~pttĪUP[[>È#~~~غukejZ\xUUU@XXX_ ooot:!552dH]KCV 6l'|;v੧Т...7njjjpUnK??ߵ`m~!^~e$c׮]Jѣ7|(1v\VҞ#Gp UQQm۶a-F/\̢yyy|2 YH BPP󑒒BC{2 MXz5ۇ^{ WMggg=ۭ&%%ӳۦ ??6qY|h۶mJx'w^h͛7QQQ `c0rij7رc<bx ^+V`ƌjVVVb…8r(½ދݻwC" 99Rݶp5$$$׷Cc<e̟?cƌ5r $$UUU(((@ii)z= X>90(..F]]jjj@40~vgFFFӧOqD",\P4t^rCTvxN @CC^}UH$Xl{9LNN󑛛8lٲرc2pϘ={6ѿ8p py=z^X"""AAAxwsv* %%%ƍ7`0 !JL&X,EQ0 h4PT`Y: NNN 鰸~x0h 3z3gŋcDg 77./P(``~|vZDGG#<<~ aၲ2.0&H0jԨJ$=%%%HKKC~v@ؾ};}]<]֯1Ěn޽VAyennn@t&'?ʸkAb`mzz:D"IHKK^~:-F s炢(;weeepqq_~jlݺj=,OPƐ!Cp 8piii?>f̘qKϝ8=тݻwcٲetH$?^z GŦMbŊnk圝m|ڶ8ȑ#MXrVo>!""8]}gggPV!/*Xd 1arjSQQ[ԩSJƒ>={Xng+V@]]ƌc'bΜ9b h5jpI 4ń˗/#""׮]CEEك*'W_}ѣGcٷŋUTT'xNL&s=^zH<:t(&OQF b WƗ_~}ga%>]'rss*֦eY,7nϼ^,˖VֱulIM6**pV6((d2v,˲_.K4zj6))m _^~jرcljjs~lLL >3ltt4rJvРAVYJر}뭷jo bz3gΰk׮eϞ=3ű*%t 'mڼE썒JVѱ,˲oRmye|5\z@cN'|^oi֬YHի  `_Gd2e lmm-ri,[ qqqǧ~ "==/_Fxx8d2r9VZ.7AR~Ϟ=xgos;4 ֮]#G ˗/sB b &LqXwWU*p\.vwùu)Œ3ϣg˗1yd,\]sˑf!C@P !!#G4tBo<8{,}cڴix'wxG+ر< #Gp¾}pa8::bҥP('|OOOl޼Y|M_xgQ\\0ݻϟGnn.px`/7np Ҵu˗//>s k\/^-e-eee8s>Wtt4N:///|Wꫯ0 TUUaAbb"p>|,⥗^‘#G;%3mŋRHOOA4xG9fϞ-Y>|7f͚%Xk֬syGzz:+Ǵi ݄JJJڽ]U닼<8::"77XmW!Att4Eqj&O ,W:u*Ǝ{bӦMx/ʕ+t~..](Af#a޽i6l0`3EQ?#)) }fm[/]aڕfqK\#**k(--`jlرc/_~xnMee%~GaܹXX,?~z[Lwi(//o=Z%EA.)))(((@HH4Mƶpx;8p +W"!!/^?;v 66E M駟O?!!!oF^z =7{۶mvbbb0g:t6666mߏ@͛7oƑ#GqaŊ*/"ݯ_?YFZZlllSwő#G_:uUfgg#??mΕqwwGtt4pM"99W\cf555(,,֭[qƙG:u }_{[;x:5ÉEltdggs ?-j i١Ƣz$%%QW 3֡ |I|'~<8t>CHR㡇7PWWݻwC,C$eYznd`̘1;w."##Cbɝϐa$&&BP9!V }f//¹3f̰hD]]Чyzxx &&ɨiaTVV~~/..FQQݡR0pNӿCa^Y 11d  5j5p)A㨬D >nrߣLwGn 777,X@)Sf͚vɩS0c >+WDbb"|q=pC $bu 33K.ĉ _smZ-Ξ= ^hmBDDrss#GZ6Mؾ};ϟr9C%4 z)h,@` eee\"T{<P(X`ydffŅ۟=++[ֺ7O 0 gΜAII`MkXfKXZvak)l`ҤI^p*=,, (((+111HOOG\\e[=T*g}_((((pww0#:OH$BLLmQ_| à&8q"P^^gaaaݺ ڐ!C{n3 $/]'ϟGmm-R)WW^o팻;Ms!>> *jHOOG]]]wH $$ȑ#QWW 3qwF^^d>I&gΜUuOE~~>]@9|||ヂ\pb=2̦RR899aر$Op+/JKKLLJ[ +h4(**BII T*;;􄧧'j5Nǭ\nq5St:J%Z- 8˺z\@r VUU p+ŠD"P-faPDDۓ8 o5 XEQt0 i;F*ĝ>@'o愾uKp'$@\/ @ "@ @ @xO q@ @ 3@mg,C<@@  DN"@ @ @@X9(@ ZBL2bl ]&`-ȶplK `[X}$Dz;Zl/VFF%Ɋ)ӟ֎i 1{5Jb+7?2)L>Z\ximb;/?;X@_9i~X,i:b}.<ˀ u6i+k:k030Ιbx;i9rni:0xϒmV!i +T9M\?8Ԅ `f!Ef_%ZQWKΧ( ,htL5Ωƾ,3VKѦ4/;2Jp?&M5=km2L2)"6= ӼgOQ( z@5> $1c61C@ @ "RHGśw Xy}$Ay@sX^ sL09Ư,wQ;(4 "\yߐ(q{~X&>o 5OKA@nL?ո`cLHLΡXz=5QY M401Ke,@hl"Vh`E4 D`I@KQ`a@AH]Q2 >B% R"c͂zh^l4}s0r9y*K3cYG UH@ @ "@ @ "@ @ "@ @ "@ @ "@ @ "@ @ "@ @ "@hJ8IENDB`mldemos-0.4.3/MLDemos/icons/save.png000066400000000000000000001104331172143270300172370ustar00rootroot00000000000000PNG  IHDR\rf IDATx[y&T}vn98n;'9\ ( M qnpA"qhA\pA`$H̀hFvnnykZo:}ʥF$o`6zq 6 Lh4^$ιOy/[piB{cs0p8`G~)%8C?5nucy|?aB0>1bxq:xbs1FlGxut~7/ڥ.sk>}9sqIJH)!i9m8/Oc=%` 1qgaI-uѸ6HyCS ּw?ck@L Ca*a+paGh%/p-S14~x7KxO|okp8SN'f$ԤP'/> &;`2;Lcz6Ȉ>cB%d!p7~_? ! *>eyB0oC___kFW>zn4ƈym@d~O&MHp0zÆjltE$$$SDL@ o.>Lӄy[1FT&@vo0 ٟY/Eo}ܗïiyJ#u5)Nizd~ , G8ή@XoZ@JC1a !f~;wE@Xsw-he8n%2cY )/i+pMZ̚븄.hs4iuY0P'Vp4M"P* ?ԉU&9 ޛF ]ks/.)#Ռ1bYCѧ@ @c-4 'R/ =4wq7|_=1!H1?I|O5MS,D(LKW̗eQ43Rĺ.o0 #b ̈́:_Z4loǔ7Z-{alޖe,f2T |TğItiLdBi;祋8 t*=b]2kv WP =gI>jBF]Bƻ4ʐH?]a]S!CM 9]QCWIf8C:a]qs^~=oq R\%Ѭ^"m6,A~.>@Lv.՗O`Y:ӝ&{0ݗ?.g'w:,^>=`#[|뭷[tC%02\*5ր/!A,O\OD_vGG0,w"fN3kxR r0UC%}Q||^z%Xo7XJ?NOn˖}I5^Kʵ73PU+_6W!^JNCUd硫$r+|{xmL|c,*Fw!D%SPeflt R_;eJ˲40ƟWFfƅ_|2X8?43N>ߏT% p(.@/!Blui`w@*=1xn&6b?>O{^2\TdSX{# P%t h30ioOmOo~v η%?*h{ɹ,wpi4OS(P}|sj΁» T3'I, [i}!aYO?F 9?)p.54m)6wծh3UT&4X ?5AzeV>iD@Ͼ X0T-_INA̕mqJ9?uZ# j=(nH9pSTS~ejVLN'v; z&de DF;d=\#7 _w֮XG9KAWDRseBn.yZ7Mp~ U$F#2O觰ޓ~uC>N1 i9nف/ ^\n0Ǜ=n95YMBA[i S!eҼ"q0 npF +t}!—]a4S_{U8-~9a t<44_tT8' @g,8FRf2ߡŴʇIڅ?\lti6=4юECpU .ZYA(HJH (ײ9wa7E霳jӶ!MuضSV5xh1h>w#S1׼*}N>IS9!t~&V$8F_d"c ft-է)A69 ` 2;B&5hkHj=Z>LJRoV RR]ߙe:Sqi3Fܱ?SmL@3E\m 3yjw͕Kk׶`l6RI6w$?_` #E_q0}{j@8\/o sNwRd +Ί20tRM@6pkPo*\ڛci~ 溨.3-n'fg_\>koGC7)>Y9VQ-`bY K9*>)~P˂cV-4Z`IB&]Fm84(0׼2 WMKGF@30ZAqiN F[K09Z9p6^@-Pf`f жW*PJAFl[/DE3@!!弴i#QP9(S5nU€d\4.^7ϳmr@?o2'0JF]t]i0'Uf|YٍUz0MS1[0RHk~5RZcLH^v%sFQ`bwkE\S 6UkW-*ϾS60 :y*.ZO2=Nv< uS> $6z%cď'۴\sf7lwsp '<>!1Z4wiEU$AAgj y }|)uxs~O-u s@dP2~U0$TAcm< OB&4H.U)vD[ q~z}F]J县0q-.-}WKA`{Wޡ@~늁SnY7f1(|PCN)m}Ģ0t(Q0Q[݊wZ Q3iyV:\r hqM_j(M ǣIy 4b1@ Uvf d,>AB{=)Uh v 繽=|7&"1nxݾ]Z׌A͓t`=^#N_Knc*y0 źj`-Zos%eXnB`k5f4\z=N;y uTkT@y\P*Ƌ6rn+|t< P-9@cހ*Y7k* 1;Ӳ"Ĉj*PIfh?ᴨN d!!1祫TBQq2? 9@͡BB|ޝ76?ǔe{ZfJVU`_!Ȳ,S(VXۃ_Lݱ 9y3fJsuŰI:Gk"<9bܟ7`F]BB { p )~Hv`y6? %]x]W %&򽷠/qS~ڲJ"=CfYѵH/O:M 姠6MmSB65W`]?/ f40H~ j)aXn%ԇC@Z[suහ |. _Z\ d(r:e@ {-!J6Ȣ_/r7R wkvSIjlXnLZ blz&<+f 1":S%Px,L/aۙH1 wMlt-lQrB7>: F]UΜdG.vD˂U 0dccJf h_7~\}cAjMfu$ma/4yC]}~ץm8ty@(('L#,1@+j$fA2mtj3J&{17 JeXsawňӲ`&,6nb莦hs[(a8dP2ajF>/cJ=צ6ngXÝjOX}V`ޛuMKREw@$2Ek2U|!kȀh-6N39, ?Z xd\ O)ӽKW %ėRjjHǔp<0sE<;DnCɪ:n UIwN1t$e=uY.y)oPpGb̀o8ZW`r:.}.;AQh&O5 rގSڬOjh]BbRiJ.^NfIf/T Es<}W:А MEU*X b.DX8p6 vΟՎTMzn{hQ+Ov׋gg(NCȠy5EcZ{3u TKX}?\Ũh##[]yXE{CAb6 @$1O+wJ=r4](xLhʨ&@bcSs*b l.F!6qe3Z- !XPזXbf@V|՚湪\_{A 5 $2B_dⲔ[1F#wf_ ֞TR53ߚ @H׿]$Ykw}S˓ii*12 >3cK0/ѣ@9PhKZ.5Z\K1-e^y$lPm IDATtX.1颱]|Θ }Z̭77MՂ6}.\h#%2#=Bos_r[C )F!54}e{o{f2 /͵ݗnmé0j. iQFynbZw'ދ 0s61tN3\Z Pg!?皨V%, vx\N454H u*tb 0pLhKvjRIJT1i1=y H p`/v}1|OfF)'BpmCBs lѵh)߯BkBzwFӓ'X.fԧSP%^3mB}XDrec ٭Yƥ#hL =QrH~;-ilKy ,bߤp*5J1j/P< qhD =ϳO3I`\FפToJfaܓ.5`^_m)~&.~,]@z'kՠ:d,]X6d Ҹq]>U_өO!Y'-yG:x<׼N W \$i/AϿ :P ]88W>`t.' y+k޻?j)%c*ՀZdnfNfOt1%X%`(Dۂ@}D!lFW"Ss٩ 1h&{kl4V%t݁ɴk޳Rh&\6"O?{qÙ mt )@el[OWЛր 0Tjhcs2#*$լQ3B{jʥS6&:͊y-UW[藆 )x(1ɓ?Sz+*$h 31.81zQ?hRu?'ʯ)(O^ѐ |X50X$.(2f7'r"mkMFؿ` Mxf p{탩)jIo@r2JC&H~JJ6m@J>w t75\dɴs>' +i-\.z< kٮV6ͱJ:uzC#5Zc`pJZlѵ(lo_-:^eY4 5)ӋpN}|j~2vjq?OU1Hε]Dtm JQX~s7{I^7>ƈmc%h8׽Ǽ݇qMPhb{,]`F^GM 6 %&t<إgù46)b]ۦ$~x,zɕvRXA5},]- npE߸Ps;9Vh]k_]|ccqͧ/U@%y:T_La.cjՀ0ݩ#b(,#0\Kx  =4mt Su뺚5L˗|)ۈ+f@˰,,\!Ԃ٤!5eB ͒ha?/u'۹ [D`kQ97 M XCmڷ'E/|S"dnϸ_tG yS-MNM2:~7R~J`DzxRWıF%2_%O%F<=7e=5ܐ'zKn{#ckX0ʶ/ĈbjFSd39(6A&̬}o<9yx6*)k9?~_M<_55dڗ$ x,] bc8aY13\L8 մDhyd+o7~70oⓟԝ%$"<[YѮ䥾I]h4O}0OBQcRz !`Y'OޟuiaLh{;~e iLsg&Mjmƹᜐ8F~pS>׾_e ax p ]% d&}E~Aly\9bxeܾƛxo}@c+ss!` =<GL3uaB;,4?8X֓|(ߖɓC\tr`ZPUۅ6Ru&<\ +3y_yX?Asmgk^1v04 %t;8ce=eP\mQ~SwCS 5O;lΦq?3 W]6rl{X0 f)cj&li23Q3iEh&7ǷWƥ;:sGA|vz0iȰڛ>OV) 4pQ{CJ&gH\xxC]$Rzc]oG8\Q*-|ZZH]ypXs0"CW@8!3k-KSЦ7U{¼Vѷӄ'k B X4 3TS M$f}jsGZNJj& Tn޳bhͅ{SjIc?^jVuϸ+FRt*hѲHsᵔpTXhkUKS)8,)%i9fe#h.ǣk 3 kXᏥP)#iFI眳AƔTcyt:haUKJdz.ZNGSN@V <UMyOubZ71.>b@ nPsѥ>|Լ1p8ȜzC.{PaCw1Çp>YPe.Fd8SaМʙ« V=F&DJsKW #@`)[Q )L 81FӮ({SPsjb2'~\P65j,1jν \ϴ.Ԃr |^; 7tnxaWz@1FpL$sH>ؽ?|CP4>C{ZTx]Bq}B]I\Ӂԣd``i9bϿ9P!Lh򾏧1Eo2BRԿyIjhEKDOGˀg@u( sm-$23ƈ~o&hWEU6:=ο sZgF@8Z1İHgV1q޲Z>Zv,ȿ%u=@Wh *LX.3 ~z V?T1^GA2Gd98&(q4@ s>=<}*4 ̯V׆CJu2tiuCxwe5~kXyy{\jL!ܹ=;DqsR}j_K NiaHҕPιDS3Q;<y^V0j \272+aCmBA.XTcՂGȠy .~e ӜB}MD?w'}>ԕ`4zb) m^fZ9-5.|Oa13R Q Ր0XvLrYaDx&D"dj1_ꠋh%2PN2VS=ϥf.燯m IԐ$IK Um߃DI qw ^yOʈRR(^B!LDY}>/#Pq4N]ui_441T%ag I_F֐Cx^ ŤJ[ji91i(s@0(ήkԧ'QhU‹{j2 ul8e( BN TE|D]MHW ?>]r9SG]~׻Tu2 #ZR2-`M!5Dy.uh9P؅lmA;0\ \5̥&ƗSʉCtj2t_,@K'ϩ+/kmc4DW0JPsΒ~xd Ob5>_s bF=jDg zq{>V?1i96@)|~Nדaˈ($b< ӵzPK!3/"Ρ$mh~]Τ x1F@1n>l)Z?;gO$_L.5c[-2LtC5zMN@x۸?j6sltyKy/`z/ڕ$1y=C5a6PKBcvPkT(#`Fr]]c+ϳj\[]B)3NԒk`u^GZ{j?=/]LC(Dv&c_J%PMk ( ͅd[]6h x9-pv<팉RJֳG}Aw4eQbp'-T]D-T>e>%Y[]h2jU^7c s1kWΟ# Wj9CT佪̴2x}Ly֓tl3@Ts f-`R=PÞ),+cC}0,*`4b{VfPJMn>ki x1jD}kD5|eHckŵa&H +OI+8YXEkRF評ǵqW1tD K{7KaUZ\T]֊^qnBb@۝Ў2b8-54ӡ1K&3s&Ȉ7=KLM Jj}դ/ .uVMs*Xc<>'(BkЬjWiM&S5NʪXcJM}aLըahR8F6dUe4@-(607PK9Ђr[#ɠԜ0ഔjO5 IDAT7uAG;t^yli$B8;Mx6:^.o %), RÀ] zyL=KǎYi] :/'?8X jG@JѺV8X\|b w}O`7-_]0ejK &ZYc^_BWN62줒sjϨdqFTTPRCE?`Hq|_oq1< wsc?}8n?q[g>qBXKaMh1Ǒm"G_,vM ob]P-ihomXۦG$bH9^{^@6`<mrQNy(Xx xR2 _wt~'+q{{\cW>p"9:'HxhPWU|?gDZuR"H:RB4#?5“' xη7^G{p{{87!žR@A ǐ{[8GEbO{]W :djmH1_Ÿٟɓ'=Lc.&'mkv8 w Eҳ{?~zkks^}UGkw&6}nҼ @da`V^q4~v$.v$8IxBhici+:cܵ p ]+o~Ї}߭9g n[?E;=^G}a]G uS-l8J~}8'(Hx/`1BbRM_}\]n3PהYmD=#S ѤXBmwC7g>Gˏ^{ {ﵚ̽&Zb-O}}n!\B^T,{k k^ynN6w gY|_ş|\k+ciq}!xph1TEjYs0!o伇GVKk ‰>/{"g bZi_& -o} cdқ&xWs{ͫ\"E8)¡j,v/c~?ܹ߇4c{ǹ|[I6{8EOӔsPӐ5SJo 4 ș)RhYDT -30wtfƈmb} ~)FCG2 jh:L} ׾nmXCw~̂3,p##q².؍S1Eѭ/'?y=,gQN׊G΁WbG]|m GB#U82Wx e }JEXNƦUy7eӍ51ƼDSP[ĩM&jPEU~N+ǖ۶޷;a޿{_~471Nux CW=_1L3w!,i#F+mӕz K5C7ﳮ weT2#pl7d12&5oV+  OAB(Tr@rc3(ZsN~ ]FU w7!%˅?\JH&-נT3]?7Id"qe1k!Ӏۧj引 5 4\Ă~ws>+\ns0P xm`v6x];iVS5VRIET@) +ksz[;b ui[܄v8է1I1Fd9!%x;(E@_jl_x>Nn*bv4_ӿ_`JTä@'^ZTi%Zk0:?s-|*{PyMV(enY)紭儱$zruR.&L݂祫[t[dkSP%O>|Jehtxyְ6-q}4Wn 4MqXN @vYy9z{x?wO"Ԅמ *R0ʶ$+ں/LJ1"zofnY禑218 ]M5 vSX@;mHw6@joDa1 Qb3@V „kjsll<}50 ;.b"V i7CqCX̲RBoX#=_%K*xy #v}+T (D6:Gİ٬X,H\[(p=K)/)vMLa CgxV[& KD+Sas9!\He6]X<[3I ?5xA04.XMw!fs})Yg=>k,8O͝<̪Tnp/J@ [Mρ-h0b}m&0MFd~@͸,m8T|;ۄ#%ׁ]J!Yֆd3 z9"ѲC|9{y굔q2k-wEkf,@B\Y4C 49*pWM"URy/VC9sb@,z2o@A2| cñ%ՌOkwX"烿}ut0ncYfןLTw=dt,{Swݢ>/uUAkJ"}veH/5V>jrn }Wπ|M\\n&J O,ud<mBk1s ov<̧`8|LVR,som$V/9T]V?N}sg=֠R7Y]/ qR5@.K]?R2䧕jPnAg,ZNI[1d.^8-\lp:5,^*y^N,; Y zWiJ 26A'_8X7g}Hཫ@*D,U8ΧZ{ӿ'Zb8t:a-ߐW;qRi,=gIhr 77/5;Ɯk@K;7˻yѵĪzUA =$B@Styl MVT& r:C|;Hj `i%gLh7=r<1ÍD\/{{К8cs)wΓVqX:#JIn$+e/u&|6yĂx?:vo'9^g| u. 1ԚT3"OcޜXlR] otZ.@ 54J*i%ޛ>`(-IdS_~E`6u`p]jsF/Lkf;msߵ:&LD=e h'WփTM 75.Mn 1W},)W:P = 5LphB!&@)8;-q =Q-$h m>:n2K>xjLysUP@`"ȼR׌745yA>~ToJ w*v8R|J-Vޓjg2 m܏r<7y@Lŧ5>Zzq*`H=)E77Xk 14ץkރ>,d}"й}֏Y,0zEs3i0fa]EA!]z|}·ozV&[CŧVp7XT,q1} T|j莿!7PPkU ͇aؽ,t ?H$T-5CC0X%'ua.T֜@Nv 'Xw <iVv42wDf"ɝ0 Cu 1N;W g9^X)h> :^2ܽ An-* :( bc%Y杝xm OW-VR);$0 .kMpe.gs41U!YRo<5џ.g>=`ZZcQױLÖ\ _MǩnQp9Za]x?ZwV ^ٟdA &U)S@[q.#RS%Njb+4> ?@hl0LDq gplaѹݿz[r6{TE0?@>!u]q%uG 3{q8gDtvE1l]_c]0;$Z=M)|_/5Bl@具 *8e Eu)E󮑘O_M'ت5 {=3Cmis~ot!jSZ6O$4Y:LlI16+F1cWC`uռ@}|cU(#.\v:Oeh*,qMn/\p ʨZkIz¹r+C &G>%Dvd@-%Lп>]ZyK}>u- x`h;zi>$ ]^fg_7jޞ'4MYTP3d•$l 9'ĵGȎżD̪ p.kN{zCt |~АEȣ sI$(&aA5㏉EYM>8 ,28 x3ps ι h 7+-.ykB5/f[3O­?Ϲs ? sY}@Msex VT̈b[SH0k e-{.5}:KNt5癦 B ƅ[cc(L;2v$g%ԟWM!>B29И-یR 4X,U1}<ß1b2uzGCzOj1sޭZ0[IXׁ~Fϵmر#Ek ls硫`1FRQBG:3jߘU@}h Huz;ݾ3bc1S>bhB!ӟU-2f, Xpljẞ1z!pI+SMǾi}gr@5bWΓ m*u h-ORkl`]N)?,=df҂oո 8 %>mG=}GMYabJap<lè>De2jӁZAV@s&!;Ռw45iM289Ӟ y}%i;}InZKt}xV;vy$Lj:eO;k `+r*NcUdZ>Fd{gqwfWttI7WHDT1'^ AW=z@%RŢ_AAIW!GBC$e ޻b2i|scV-׃t* &լW!Hr#Pܥo-sC斛2k9ha=m3&8*_=ۗXe U2=Ӽ3&D]W,in5OX5ːIEj5Ӫ}G}! tϧ`;mNg'zw@="ZCsOpi:w Ši ̎1+x<yi5 >n׀|n>ym݅S,O¾&<,zK vL& /Ð2?CXXlt:{?5A"xtA*凒^,c57H ezV3iӄxs[x .P ,z_y;ah6kiJ1 $>GT&9{?c G d_9#YT0 |'@ NBhwg(Rs]NŬ~n6Hv \yCEm "Z& Ԋ.W1>̠͢ڟMQ5}U+Tb)2ϥ!jrnI qP+\J5wXs^[2 <Oo`\37 %P*hM-[ntfo?.Oӌl\]ܜqX X‡ x{2Ნpsxq3S Rwڨ[kkα7H=W8ԏS!pK2S q粞l(]" Aj"*9o)-*Nt &1/]jl%M|6ܳo,%$91V&tK vi\^Ϙky330Bfg[ &q~ݷZrȪ:V%[FvÙ^c Yn$,&@}Ye^O&ɌGCX~眪" Wa=νvEX,~O>COi~w.->O!\ŸKnF{y'2v BR4#'$S\پ&Q~`b 1%] ])Dk>4#Pتkթka`v:W={*=uʶevcĈ9U7aě0qX4d>Bp\0UK6Y=rݡm`pбuگ`lL3.aJ &3ۇ:Y Y kQxS0Y_CNuABKJoĥ" }\0ҧ ӥ\uSR E왐@0$SX\l~"OmUZŊY;b@툀ʬd[ec2I42VI}} OaMA#8gSUzI(M5:u ~9rz/)K`L:TX߮V)=GύZ +&n-X2dmY%Wq!6w}6ѬF VŕK MTUnpT rk@puw d71fE|LSTyr3Z2>)>9y2pK4 &Mcs 4s"A)iGD2sI#CG'X?\Y%OhmPKbfP?>oBfsc趦Y DړV.z!}rD ~8Y ?)ncE@S]x9z SuЏ,7&1DetPg3?ϨBr93e9E b(9~L+27WAݥTZ/yZp Dqa wւs(x2Icz2voNٻ^ŝ^|;xruqdk}.%q9w_"`r<wUlJgsxk2֢|} Ƙ&t26ivW`=;&p?~ )5Dr rpIpόV`ZXf}>u$-')@_rTnV9F~͆QIHuʵ8:-H$xBBPGeoBrh:3k -=$_PH8\\{I}p%pb-m'vRYGͮ@P8Y๖U& 3jNDU⎼ȁRO$e>٥UU=046mS ,b)`L{ϤO}7)=(G%;Y( Q1>E qLN#\pNngs vAZsqn(r9$5V*$vpt I E'Mh. eyd%6Y1LsZ%_^DhA#mi+o/iBv[x璙Q#KdNl.IQ{;yu- Q)rա\̀숌ýH\NBɾٜ`ZglV 3wXndY }bY([ H-zYF L6OvmZx6I )=wʚeCmK>R \XIK}$I%Cq5U$}ꦁ91f lj}X _߿+W^o2)x+wK' :,Hrhv&?\x ,RPBɀLMM@-*7YJ)]ޞH/Id؟fa?*%$@? K= @1F>iJŗI".zʼn3pj ::F,0,<.qxu}⹋vGkiETJ}t[C7al"./tKg%KFLWn7*'1r*K:M=799ICˠ[E:C)P@>*"CiBrYι=uq8oCz]eNo.|&brcnܮ^[#b;Ť 5w}owu/[@]}o"'`vSVM<LauErRޒv%eϒ\ɉ%$*d;4G%$"1"}VGatTBb5%_ÑIf`kp KJ3^}$uEi{>u]v]Jcy'y'a$"\n7ޣY5IXK1؍{۪Gw#`WWn$ ] j p3v[Giy$bHXA@EܢOVHc=c7pQNIrTօ|оpttybedP'zgGGGeg7%_Ah! 6Oϒk࿖"w6yR,DMnZmt}{wnGP\P `L_onf9")aլҺ9T.n7i@h91Șcs" Uc~`QmJrH%RiQ|=^y詬cјƠRdzR.шk[\~Ey栟߲m^˳NPu\RHWQK^R1&r=9y&ݘ)ʒ`1zM;v5yʹ aΐN {߼֏>tM%l@̥L<SV +:G%ͨ`BɵKŌs;w'X ^) l=AeЙpcrAQTri+'NU3fDy=:7!\2FKƐȳ$ǰD"?ǐU~scF“-Rysڠb)Yk;T=?m'Eߵ[QhW*0<_Οn$>Doo- N)xbYWn[OdN-[><_Rx,d7{XO]~\ dTфʱE8K,ͬC m? RV¯pKd> s,BYAH,)۩4#ϟ֟/D"b=@هVp@R&YPptt!mn skڱa .a}j)mLZy'*e1ּt""*κN=ZѧqCԒKI|7&_,NQ9Ɩ S,".R}IƸ(ޏXn#oRU=ɗp$K%Pjn$;<֞@J)Jqt%dj K\~+z䑅' f}[ULq+]_׿{aEZc=jecFtv!0ףW_ŧ~Wp!,J O1B8B@ νr?yUF/'xw v'w㝋&$ds{~ DR<Ɠp=>nbKZp# 2嗳6-5z㣏]"N@Ī#!S+ݽ{m/'gzXJSJ9e o='!C {)i@3-E`RQ2Ge18:Ľ;_xʸ6=h11 V4ˬm[+[[I]3O|1NaOcDNݫdL|wDl`$ul1YEDG,'L VmI"Bk K:Facu ~{\{d*Y97nc\y5˲?{snprb_7ˋwO|w N= 9C]1} ?{?~&UL=Xcd@q VjU4(+.WLjcw9m'c|O:؆@l>"VrP"(O&{ٞAH\l[pĪ쳥Y\#UuOEI%D[(sɪ1UP~{c~c} u=4|cydy7MӜcvUUupHۣP/1`4D.HI(O8Әr'""zk7aCyWUeb~:cLe{~#"R02_ `nxѶ\{wa"wQ=.b? t&CE=D{FEkpezWeGGP.]oy;c[kTUZ{Rm4;Cl:@zI.` `"'d3MQ2oh},1*oqu]xs(v9MmƝZk8l#W1Hѡ"XCdL _"$ QFAs@u`3{㽷L1_~ o\l T~T&ZkOk9i9rJ vb$pVЫ8AfkU=3!'PF $`$" wxk7M㚦qZZ17Mkx6(wYX pZז" cQOJ":`=Ƙk$,Kp%d|HE$²|f"Nsp3mV]m:s ˎ[@Y ^)/xf^y}۶1=~`uyۋ/Vڵkd!Xzd!P7Ȁ_2U-4Mcxu]׆G|^3i u3L]׈@;>>v[k}<|חZk@(r5 8;(:O%P:k@sKRI]uFB=ڶmۚum8L۶&@k 5BpyG@>h۶ScZjꛦuW^8Lq Kf^[ʋ,#^jJDFCZKcL`4cyu~[sZy֕c$k5?Хg(*+cZBsFZED{ml0$I.ާB\;UN_vDykϨXlߜ3=-1JT#{AN=_lTK4.sgc5FFJ(`.o39N\!2ROp(=k?̨<&+0MQ@(y Ke`ChK=B '4{8 dK@XB0,C~~li èYnS#'0đ@<7/~$_~DFԑcY?=.2NIY4vJ84g>Ee~@Ցc--2OMNpYfb9 0K]^ Seil_:O3꺔g @F r(Zqh 46V`P׀<c>4w.ishK4PCcC: g`qޥDKlW"q&FSmuȡTw=`2O!RalΜ6`4Śj,$}.d5 %ۮ)Ȓ/cPϵL? c91T%aLDz%ճe乤X\,\TO-NJ&}4PLy2.W<ǞȠDr|;C>sV%:S>ӳԔ(ƜƼXOs\K)Iuҳ<ٞcKS@裡XiO]_q,isJg0VmW+,g C*"'T<@K@9)>$ N=)$P/1jtKrr\S=@ƞ1p"0S=xJS^]gziʌݏ|/&P2;=9d0vYsHtדYB4嚛̡ϦR5^Kq.oXٹ{&Kt"%Laɷ!`z.emjC(!gK~HTT|EL@^0X{K?2d m!rKz P/| Si̒4Uf輥áQ./JϚ~i S@y;͟JD}\٥mIޡbzg}?gz9R:=7gQдt9=;OryUTK> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPIDATx{lWuƜkU !!$t/ m'v8}NN'{N}v'i线 `m =HB9uǃ=1uOnccVB=xY2|׌b"q8 sg,> z}O?CLHA./u^90_:3VfB}f9qk20ژuKݽc{T&e(~ FY1Q1)>{u7XUh6;?l2 Xk GBN*ǞU{X4-7"u]ae2t: MscxE2]赾ȅvWn2r#]z v1.V};+gQ8y||=ϝŲ;%g+?_pltZQr GDl sL;H=@.q BJ2@S)Sۑ㨭x׶ ^0NF4w5)^>wsmw=ݳUYs7w*.?xDwd `6tv/+c[8@?!wFQ7q:`qm@C+[E\@ =_E P8q>6=0ЖanïAƏbGM;0"eE;5eF7,&ll.xγb}F~e{0TDCXl? OX2%:~cصE3vn {*Sj@#gW8{{diC/KBECƙzg.DEԠw!, <hAjlD?Sd=_U?'"9e"N*sX`y:{q C/|Gkص{t2|fd}ߺk1G\tQܦHm:#miݜBYGc{e,U_(Sd$} Ȁ̞cN0d#?oE;<s]L[yp[8|FP{k#.S,(>Os yz~L5G^1PLJ.h y; ,eS]4vx΀2.vgL3MQvL 8Gu0}0S 0; aS|1 _ Ueҡ/-)>/b}ajB],xmo.v=#x[q PpFa6kuy?#ol;{Ϲ(??Þ]{{mR`8MZ2\R Ns+ey/Qze`=P ssJG0@QH@)~! U 6C[`0-9T8Gַi8Ϝ2`]R1S8WSr {{vݟ+*s=::ɤ0ٴƑxw' . Ff+ٵ]l|KcϮ~ yq?} @]WLr^8ٴ@VD uwvU +#ɹȟA@w^,y>KIPV2z%A>{p's 1i.fXCT0D/%53T*n\SOɁ>яgs\z__ĉ'}\9sϬ /٣xߪcnox˟;޷=?`Əobs|87VGL'N&;vNYC=;:o,maXKgc;5֧-\vxysV`T׸5k\5k\5k\zN:v:ΦO[lx;9&h%T xlϻ?qfq|*W㶭Ʈgvrndv1Ny[/OYo=~B::wvڵkGXY]%+Zc'ݠÎTˇ[*1J)yI *{ڗD7 Ŕ'lOӸKX Pr}]Bf)dZݽW'+F3D<?ZjEudNiIO'`c b%;5:q=cVQ}n_RO&ߧiwU#:N"QdҹWYF+-?@`";# d5uB}&6#|8 ̔[H{h%;JSiAծw|z|zp'hpDb:*#p%35N֗ˇo%c9WWw c9:H`yi3X|hNtJP^UX=(ݥ eɧ& K>eO!KZ; 6R#K ڶsǴ`\ߙLJʂS @0 k6B*Ga!`WL>k%o4h&2 I9FG@$!h0dPx0כֿ[P_^} 99C {+dro+Y.b!Z00pY#[  }|<1j,/}A bpޫ_:TbiOJp9;X5 ủ?_BH@dс@uDBd@I8 #'fxCX4 Lb2iM@Y׸1 ~5@g_]Ƚ]1p1tzB4,>C) \1`aM "!Fb`1#9~4$MU5 -p=NQ2/7h{~W,dZݧ"XxoX.H#a batgڑ|D҂m1Ns׸I B]]_=(t ѥk `: **/\ > S.IKkPb"ST*P${1VaQ8~f6Ja(HrĪL ׹I2.gqΣ c =mD%q(3҃%+!+PF E@bn4\{SG<2dByQJ~Q6Lg1&^>؄@:J)LJ:-Qi%;ur=}w];ǣ8GB0}W64 G|/m`)5w At$i6 Ȼw&t )aJ$T3&g. Mt:6r g]=&)xC"A0{x!cR S w!x1xCFX~PPz>yx}x7`x$ PDb߯&0667al6q}`!ڞ\gk)EYcxdgπw.OA :3!XkPUU#sz#gxxN 7G'l&*C"v`9`d@% BB3P,@pއb }{,EHISc HC6ɯmjuSP ә$" o}=7&Lʙӄ-N 4m٘`  >s 1>*zy u Foky$+~#AAkc1aŤ1԰ƆܨP 08=r `"0,(ACJsRc@ccci[D}x 1GՁ8;[ws`=!1}F7̝`Q =M@7οiBJ0N0'0A5H4,2`U=}4z: vPp@1p_U1$-ivP*徣vo^>3ϫ1o.Ρ DsiU` bܱLSz@ Iȱ֢*LQ Ο;`IC"`41Ē""Hq SX,h vL FM<r^TP+K]ȟ QFBymC_օ^rngxHJ Ơ rPu$QF4`4؜U*kQU`* X]M &5 `;`8T<TD&PHkgرmC9\TW5~k;pupnwY D>'q^쓃4Jx04-~(#QAH !cZ0k HDYkC^/Ἇ>V30&Ёc 1Uyj0k1kkzl2HY?|[Z'3q˷m9ՀXLud舏B5 lnooaX^]=ʇ|sP#VU$jBH-<{aHx' >V4j= QR! ~`6c @Y~̬&r u.*($^pW`y{,eY= PERPvshM&5Fk-lRX*UE]%01`.Èx&1p|nBq<:]˱iw- ?Ѭ+2 ~[nv= vrfR^s4~[n~^ o_) _"xMǫnu}3k6 ڪ.U[Uh¢a]GU  Y""fAx8Ƙb@6aCi9QPei&VOt IMca.) 8\xEPGp*=Ќ?un,fqЩWmYPK/G|eF>d1N[,`hZpqU]Z,a'Rùla,aX 9,Ta1akkjL uj7p<'IYM%*Dl7T9 v%`cc#9/ ~%"e? ΘLVmӠeCIUD0Q.8=!BU Is DِTD.ʘi3Đ*帀$^P A441Xr^h^фﱲ7馛p]wѣ׿>3 }+~pmn n2@sp.;:UpT uݠm'Ra&c>. 0c} REM[0<@ j<6Շ^ ^.R؃<ȣxG׺:#~5_2e-H[/nLˠm-\0mC4PUh L&4FeG7&.w9~)R)"*,\ pSb1-xF)w=4~(cd G#? Nx[ҥ(;KC{i`(2 'PFvAyqp VhmUi[<#8zX,L&T, =wIBE$g F7 ]hǴiYa}`TG)EIY9s?3|WU/:8Q5FRo&-4z{]*do\ nmS8mK*0%?{ ~׿BG0LYv{bLP1YZ&;1]0 .Нik!|1d:5|zDFU.pE_ҋ]j!tE c%@$ƌs r -@/tyN P7!v˞.KLpZwqҮ3T*l[ħUX[_w&"3CSD@3 /ŕ_={ֆNɨY5׶Xl6Uy|ee s0x>q") "I/QLEDbI3a\O`8A>8\J4è5`K`aAk (ܶ;7ۅ=3[ge ?xѣ[i AUUN83طarUM&AoѵpE3b6j)`P 9 nD4dxHCWL4)EMȺǴ; J5? X~$xn%d}!C,F/m5.[RW&=(ކBwM7ވOk{ћos]Z~).@{"pY :J9L(^I~-3ML&cD༽!X #cXP0]!pa?*(6H {;?MGNR@vz@@YrF!̀sܛw xȀǼim;>o؀ }ɗتV9S? `^p m1PWUч7#r !+OSDTC&p/qٷ e}hMx@VD/V+GJwzk XxN&on˜uW\^p<~k`~+^ ` IL@o8)bQ?8t娻n"YB0h@ ciЊѧ-;7(HT515Q8T EmJmۂpq}@ aGJol.cb-I\7:VU%3,Za DGvN #߼x>o{q}K7 l Tp\Z UΪxk;0HNghZ\$?cPQ4>|JR3`6cFZ= øweyAF^1$`#,hF:jrN2rr'`ݻ7!NeKP=Ih(m*p2ψp̺fuޣNa6ŴtF> @bڻm0 a .UL7%?ie*Ӹ@D=|!x"꺉IDkX&faKc ԄZi:pN%R*-,lw$ }9٪E1h}%rt,Sd*X~a8bf`NL0Ր\MH ZDLfgF5Fߺ*@"g*U~DEE }3# X0b.D1JtQmPY _Ijm]8Jt)<|ΐv@AIt=>|͸`>/Ĭ(E?#rd 48`N-8p:e? cuꁊ ToA,.B9[R6t"aP | xDoy)Ra` \#ND#xH, RH)Cd^cxfwc0Kd@bKiRO0+ާiL;Ԯlc$`x6Zk .:T£:"_%8sę3w_˴:O?P~Gќ*҂R R8v!Nn lN&)3t}əzQ NAHDqaܤz'Lf 0/s !tC s× ߨ ]Df!A:u1/.!'Jn(I^|Z ~C 8%*{Б@L!:6V =nx߀뮿w Pdӝ}Б@ ,='KgjQ4uvfx7U^8 Ee~ߗ^tMo_2>\sx_iEF,Ҋpg*r~NR>yDK1 wcϞ=8rs/w@s:ef6`:'!!pQr^H}Fou= _ciTp~3e5e8Z[{?%\u=$cݕy$2 GmaD8V\}vgz_Z\uؽgVw\ƶjwv3cQD`ץ ^$S`* ছnG!uP!T8 קwWfz*52$Q{úլ: xw)M`fTt)2hC()^+| _g?!~(Ղ\7 Q^ݓI&^Jh+"R) SxdmƑAب4{J4D41c/vc pP~k_kҦۿ[;׼&\S009N} u5+/lj l@x$p/dIED Sf,`4* 2{Tb:GCTbNF_3=䓸롇pg@U(PufߏK8{7~/mMC|WK/}qѣW"`S6ãtt#Q'nesTIQ`e6 :)%uX}pcOG?rx'pO𛿉N ?38gRp;pYWaYu:"ޟiڧ>cphuu( a#K CD'A(,!VV@UՅ, )ƍ%18x^җӟTzw`׮4XEއ͉HNrv vq]xl8s=d8HB9ȁԅ-أ &!Gc`reRlԧkuo󛱲{wG4C'NNon&>yxNj^4:Vrbř˱u5 #*^u;ꖼ+!Tm X=|.l}lI%h,.I'>G/σl S C&P YbVw5DXP4>(r K﷔8#cQG,<9}!&lܹ }ּs8mq 7|+p*G"7^YŴC~s | Nmn}]w?v;߉w_}20D^&d]b!m89a .,Ktŀ`]}K?zRNUﳒaDE@T*A |"k)071|!P:uc d.Ӄ:]E! t6$# - ll,}7Pȯj|;pc} oy ;Km} .IQ>|mqgdG2ଡ଼By-)AF̳^=c2݁ ٻ/4z ?ݖ"Vx8iE R Ů]XJ>μ(R jL"7"? h2 F $՟3prAꝳ&/ףŢx#W?S~݋W_uU UP\`#Gk2bkqtJJng_}l ` 0r9s j& L(}(6 `~@>Y=R"{7ybzYD "('`( FFH 9~j/%.[UMޢD,98(/X*ȧ1M^/ S"9k_r K^NQ9mcgȶ iXALq (N V $Oߔ8t}\ ]+1^6jI.3+efH@D 5 wTg9R8ZfӖ2jLPl7qBAѩ\8]Lzchb*M 37oJV^tE; ɻo~8g~e/(;"d/a(821 Q4d8u&:w7IL' F%{b Kg t0PrqI 4 V;s.N]F|A sE {d(Cxza&P\`7@uX]2Ym{bL #63oahC/ ǐ ,s\`H Viv1NT|Iy1Ѫ 3݊Y LS=Ȥ30ht;uD A @K׳ ̀rO7!*f3V`3X@7[i{I__DZ .֐e+48yX`m~;+!^duν1@eϋ- džן\.dAP% ͰЈl&OJs @ !~Q~9o Hy#fn" ҎM =u[d=ᎪeF |N`h  ءX_,?=x\z)z׽ᕲ^ٽ;}dպ=Gc:z[18r-s:o&^_ Dp5ө9S$@ (vuTϪ2} r+*$|֒1V/c%PKHaAHc.xdxX$cv:̀*fkR#6U ڴ-nWկ} /yqͳ++`°Ήz+܃x*\sae(q]w&vke;;oBzvW_9|\U %]Y5,r-PIo˰@ ݡHĄixxbg :";/+W fɀ@!gZ}nW??wz$BC_Kym/?R!Ґ\q0wwnۇW_~yO>X_Ǟլj\TCCXEV:"Z il%0gt'`e0ZF\G*vY@ƅI/^BC6Q<Կ®AftHp"3:cK9ys|۰G TKW\xcUGW^Vete"B]UI'7ߌcV;cAuPޟK)&>89Md,.G`m`zsAkH` wH d:=@hPU& H">l&[Nx,?JWf30Qij éLb ``Ejo7?q"7ݛ{uY l`T2zq}w<(Z%/A=>}[n5^W ˇ5 o,g_Jleo:iފ>^i!g> Ň!U!R0+)8$SAnA wOHthgu/ƛîdp4P%ɗnn(};;%׾_gƟt_wuK`[C:E(ul'AED2 pHΆ b;A hRbρVѧ\'"uKx0(' !j&shRj0D4uScZ׾]vnv\g=  EE!d2IXò %EXk,Е}>z ;CplXT:k/ƦL&xe},Ϝo8V 8I>k1SS \#fXxc ԅ4 2#p،*hP+P)XH9(8As7S.L&haoRQDƖ-. цO $r·!8Lgp)'HpɳK.$ ex?4p. ~YZKv1[E)Dӛx\{k#_ėo{ 0wawF0WB0ut8y^aenmE_ؕZC 1 @%xrފF± wض<XuUŢiD*F8LPퟒ9aBpb~<`M)ܤES 8DdJ)zer2A$mџ|G߾թ߼xs#{bJl:_[m>n\tQOu ~ rzO◿do??+*ǟƐ(.w ݁$l> ?q; h<8TsH􅧝jo0LC4A!v)h6F2o:3mDK=0@f 1L%bz`:'q%] P;4`"-|q<:z4rϻ"M7y_\qE8 D&"bGy7ts(H DƆ(d`$떶rR=+-=| 6#ihRFUcPfNz1k-X,hᒰ(LԞ`$ "GAP_' TheJCPcV.;|^9,`5NrѺ0#"4&?͍DQPQ1 BzTbuYlnƄȁ' jflqCÆnwK(EDE2 uE@%oۮu إm@=Af~Gǎg^r_5 /%zW" خr,:Lz?^C8]^~9|aY[Þ={W:ۣhR"J7<">'pCȂb$ XED(¶q$O/U&+ڶ|$(V$ S@j@C͏#kg@(&O̦i1VM@ 8b̮~~U40;G?>-Ras B4XƐ;I Zq>Yj9B&a8t@  2VEai3hs7^<(~~OD]U_Ŀ;?"t 076 Ri6T 6 m"* rңp@] IG^ `I؄1dPH kSoz) KnӶx)|E_IUaцC{{N!MACÀ1-ʓC%I`x4rRQ 2S8!A)C BkqmcS`ULaG 1nbMݬ y3F4 o&{Ԃ%HBAĆ)NDʀe },a(rۧ:]i4w*llnm`dCP '*x 8 Qg*"DU_c-h#6,)\sNolW_8@t4`ūË{WVz#yvV@ahg ?kA9mam ipA[ѕ` ! q#T"%j ^R̀9s``}RqJc x;23ά.R8=2HG$2@1H;N;D3\.D{O/slU3R4qfue%MS` C l!h_R=H b5޷AZm;j+̰qƤg 4{ Rgz'䩩#qٽMӄ1|#DHDA8ȁ| J8& "aҔ} H@POlX]5Z/|!hP ;SiA6` l{yltz~ C_.}}}1]@1.k[8kѴ4 *c@uIDBaU0nl}ެ@1Z@&6%̝*U%-ku 4MXz{AAE%I \̘N&[Ǐox#^rKqhilR"--PfL 4oh ,ljK­0ilxO_r\s.xCk LC۴֠i>C{bXnä(j1AĖ%rBi0vJ GOFR]OTZ]Yf8} c/ h^ ^*B*!%0y9skeqqi,\ʅdᨁw.Դ q@YB*7{'_2.ܿoouui$P:eHAD%lMY/777?cs|#x'o ?a3-\kњ1l'`:쏩~6AG!| 9V~J" E[ qO\=o,k@y?U&Øc/efr>5zmAXcam4iICS4I_!~qbm {VV_nwcwA: xq8pC=,O>'ȉǕ]ݫ[$8W=﮻;/a}(-кbkB)s;8iE2s@HH!N SE%(O٢S'x;&u޽Xb>Ob,pDi MuJ\pxH:կy v,li[rMgdyQҎKJӂrV}8!{ W]%(ɓ~w}cdK#|31mWr[\ˢ_x(ߏ'OyA>Z Zxg: ̡<~݂~8s$I <(D1tD^l3Ĺ :wk Vg3<}>@ H1H9 ?#+^*XPU` U=b* 'HD+.zN1E 8 lL&X T] |+_M݇7;oDŇ.{.z oox[0LfOl{"⋎9 1>Otf2rUUu4hsln.0iYh2h|ܶ6Jgiy4uG3.kM~ M\dޟwCE]h}{yhgRޒ4ȎS:ѵ 0^㊫ UuQk-@U`fi@IĚ}W\=^Ç3'0Q,W^{-д-^{Zw=>vJzxCK{;2/Gyy}A_c 76 L'5>? -&uN k94c4p||3P qeؽ{o'c}=wjAUc}X[_|>&DNs ʅN.6Y*tZԶ¼QXvgk4mӧOCcKv}jc=S9-a |s<*FI{\3Z'='Na>vhqι0k-?w9{w<=@L VW2ÉS<È;m[F(h@z da 7p&NMMjja 4֠m |wfλJb͟atdn5IB9?~$ß)67 c VS\uEϾ-NQfh8}zd gNs.;Efmeeibu,ԕEe٢ ʩm*QlcjZ"GyتZ^,gΜ#HAր0b"8ﻉCR%0{)PXT6Њ-E<É'2I*UɰUjpr}_tl=~e𤥝DD߇'(.r<ὃAW/n^k8KC6DjDq'뾽 T ߏua ?>P*e0B ѓH#Tm¢0o&Ws#?_t㍸1 2Gic2dߑ#Gp.I1_SU)e9ΉŪwXYY9ēO<&SPv@a++>g!6z.2:i*VWVpIރ qh@ݖ'hA(mM>]5 E_*<9O¤-|v$TYUAU:cw7ވOr ^u5xuׅkSXOк 8\5΅fcm:4g Ѱsd1H%OyM âipdܞC iԘti#Z|1A]QU.4Miж M 4p9Υu @Al΃yCӆt곺Ņ^.`߾}8p xtAch~a\ H$k,F??waZpY_Fh9fQU@hi,=Ez`(ilT43 u]cQX,X,,Ƣ k#Υ GPFr T++#o5N`h[醬LcR͜QY;(,8ֲcƣ7!}n8{uWWh] gQ4B7TWrL 1g4h TMiX '."$h*(ӄFAyNh@v;7ׅ_G#v: `ġ|뀤'O1;#ɠYaᑑWɽvUU4 EA4hmۄm]0K0Ւ]-57ۉ/[9̢'1o"s!wג}1/SrH 83kk܄s>4@X `0 sbfx/##hq բAVh6 6.D<DCX xX77qw$gֶmieNZbkҊw̰`U|)3pf+h*>FcDfttZkvڅ'Oi@ U N9s Yfr*0PLIH MjB[W*mpm#6m\TV|[Rc f++rukw1ʬNs$pJiF2x[;N 8j=m־4 N:H(iu܀. u^ZOCrۛN u-@҂VWY6{ع(DX -s;x#>/K./z.>z4y5d颊u@C`Vm\IY (&jBU5< Yc)Єqf} 6Җ, |ø3SmBJ, uH m#9i j'N+ '08eq~EӶ]ws7݄s?E0UY_z72")jL@ אJU}5اC~ߙZVVkeOD4agGd8L}:!a RΓ̤ K QYo`DMU%B炢."/. O9{<{FTaJ!jdE9q`Ǹz&({l!x9=MĩS r0"OP N*<|^J^蛆 ^ph@œƤ @6hMb,N."hP >y{`2am}s0kEte!R]¯Y)d~Ai,u)Ao}ZPU8|@J s~ѫb,DBo  ʌ!3̰dPUġm'9i]6Hggw\.}ы^SN[oE۶x+^K,|+ \hm4AI`0@a`&gV.1ס^B,Aq`uVWqI,6"#[ww *EXLmSDдuhC+x!pO /??|k p6Pť9;\8uf=V0@DNjѴ" k[GzU:4GmE+is!_2s]?CL`Zѱ7BϭuuHAtD!sCUSzKJk+o e,[;G1/9&Q:`/*:pX[k+$B{xCIu9et o"T6FpNX@*os>NrpQ :-/{{NQ6ɳke@3@);A3:Z]Y -ǧN&Q0a\,=& e "1È+cRJaDTxiCTpw>8t0pڈx:Tx!>.444Cݿ 'H rp fCllSOc!s 30. J<Ϋ D#C1c.ɓ'ۿULg3ٟ ?$|D1 ?[QO4t#EYj(' x|UZ"oOc]TiZg0Lej:ب"6VQ|`hp @ډ#Z%C?J%u{?5|A}\XYY20 @E;iČ#G$CBO{P( )MBS7 v%ImGCgke,*pΦf0x4` ,=LVv~ 0c@ݗ0fB+׽7}xc?w3EXF!GFa`(gfaueZ^;oHb!Q80=GP-:ੰ}(Ja)J6,%0Lg~ Їpq`}}# 0xb`yP~ OcsJ JW=jeUZ`gH@s#OǴ`޽؜ϱ)@h22P.JD0~tπe`X`s>wuF:@"fƮ=.jW8=<ӂ=wc4p&X$ /^. lTDN+*ZƵ&V(9uYE }LSk*! tNvl2rgAƕE]SEP-Q8=k3.[D]h6ISJ;}4~J3_.Tv,q7c;l|1rT(-̘qUBRaX6]g5ZأDL&EPNM)BNY?\=jV@z|Wd:B1ΏCv`CPb2@dD(NdTsQwL`m}#}`\Ze0&P/虌Qx,!37-s.tz4eb ,@ꚁ,e.6Q@TN'XYʮ5}pۨ)%>XbwH,k-V R1-`F`0^8* t%k9MEQY?%)܏qItKpI@V8#8UWb՜P;eLP7`[$'%ԚcG0:(A'V_'s# 85Lfۆ"eGR_v-]r ,Vg,U]EE8@vtk2QP)I9/BBGgINX>r;dPKa2 Qޑ!E 9эTF8&s{.`IȠpcCQҎ`\;_48=74&]ݿbάchPY;:%+ʾٵSvYԥD9p\J  ܅A9iԳ`FE)ACU}cGA|XxIj,=1pޣm]x+k`(ҴmG).!=ʎ4\[:cdT xEahG400@K ]u(#2gMAu3~~hR-uXǹ`[W}mD=Z]P,0 fAӸp"%Zډhk_5a9ΡkA%:x1mz gUFAUksM)A10ƆNc?oE:w"$ e¨: 5-"xib@UUiw_6( U3ƵwBE(޹йt1A Bhz$8zb$ 2Ҡw}vq8t>ڠLPUFߖH~%mzА{zz|K1 = IQSfIm׹~$t9N]6*w߽_e oݻPY*L5L¡{CdJ%\V긚<#<85u;3ci)/!`}zӱΜ>?ƃ>O﷔^+Yzlq} * XMAP l/|3m`u!)3@@k8\dd,r BK959L_:{|Ӊ>"HqF$eEЮd+2tְ~G^q+.p2zbJ\c0s`0'8x0N:b!|0r=^,9CIL$Y~ݪJE"o}d|kCBӦ(pixޅIqgf'= ׺(\Hp QBxEUU]o<>w@xTQ|\lwE:@0dkٱ>pHƦzޕtĠ9xlP4%'X[uZ1Iw[=e w.L0Ύg Y=w_9/ZR$>IB)m,Ԁ)A`Ã4#ի,P~&$ 3 7'MvuuOiS;cO;sz!f-߆[iڊx)yԺ&p p'kd ]JAY93 {&ՆTHz!2bёs\!G*e|]R _٘=dV@%o(##$RΐQ!l>vz2u:Ӄ2}4N\|%\6|NDp6p)f{"gu9 Իd <ȋ1Kd1m(Mq`hսeisHPHD]i>L1J ÙjB%!!EX:y|_kR͉cKNPEυbc_q08[b&y2;R43[kgNࡣJݳ;_I@ I|rr6Cf`HɌ6tie Jnv)q> !L0ʅ[d FWR)_v V aWݥM]J>=#ȫ/?#]{J^~*<֪=tCL+z^%G?Jb9}R6+hCl~GpAT_)Ǜƚ(j'uAw%|s{Yu& X:u[*z)Q{o[Qu r!5)> K0rV0֤cD>n@ dHJy?(rz-gI]k'7P_$2Q6 BqYZ ))vxFQ-x(nV{\=M /8Eh]#Fif$$tMID1Q2Xݺ2mhA$C?Iw}*8P}&ӊUs^@K: w`\BFePԾq<:>.{}γ9K+bo_zƶ2N԰SBO]+{PU:w]2lg|>c̓8x^xqPqƵE+1:qJ)مÎAlF`cc/ڿwu woc>GZrȳ!4M;-C*mw[wquac`6RB>MC߃0R .BORDR(#.ԍ+s<{XU%9ݥ^)K^T:fՈ~nHq'/?]@*xD; /KqCX4M:MV\kI ?u0:m#!e m%ggO@k (3ۃ`ߞq+Y_5:-vر)=H`]u շ`xMYum`:bͦf %XZ,X4ҊŲg%y'CPR^G+/w'frv>lu/!ʹ Uђ`$'i+Vc!Zg@^Zhs58m8yK/ӂQܭDeP,SÓ1 "JDX@\t< vq+G[.:ԛ_'qLJ;m>4¶i0ϓ>i)pBȾw͡L'H nh-p~Ns@ĩ?HZyG}pm3:qm]+ iiP~Wԓ:8cAtTw +S[Ge Ʉ[;E;-DއOf}:TTL"A.V]+/p9- |fIzyGCz:בAYo98=VR+mwʃ}1eh&p 1Rt0 5w!A",`\${lұv|͸/C!- hۜI8uUe!y%JoS#0s N?D)LVʼk-&u]H#@LUe䜮_ PC:Jjd~)lO]jt OQVݹ6ҼG6%f hY~&Tz}_7f4ރֲG {d MۆA˶Z8"QTҭƚoP 㱵P0on.;' 0TF!bt#x\ ~7"N5?XqB[%ٵlWC pƫC&a Zl#y~Q㬀x Jz81a,Xw;׸vdesB*$=rȸ[V!'ba'v+CWP,S "*D'YD&1uP;!&ʳN}F0sPٳZ+ $I m+/S42" $#2R\X$XoCcƘ+ľ,ENbRj 'fH[F"_1zeh׷&VBt딬U #sC͢X3ra]J+ʼ<:Fdj.Ji 9@gmy3c6[A]ג>*l6y:E 9:J =+I+4KW}HNҬTj4<V'spr|mQf\zPCQo>?>_;HSZu0ϰ!C-j#8sH_04V.&d2`i^#K9K ILlY$aXJL ˪_(#sTU5&UU'0qt:IΕK >d@RmtCga5"S.nQr_/ᗥCD.+P{#f!slnn<~h^rKՎP, ^뜓,PJ9v71{y5.@:wEs}N>9MbQ\zBh]ZFJma=ffB|Lv\{ƞ=q/=NC17/2z-<}.:rR*ɹ! iәШ<,MZ-F0s~zt:l1׏DhEx^d9&~kNd6aM-O!N WZ D,ۢ™ӧ2'BdH9 GZ= t:] |I/`XѶwyގ`o83̩_ZUM޹$!2_J!5Ju8qۓd2Or<|izч2C].j:d\m;k\;*p\!)DY1fNDBxnxe1ݴ1f,M3X˜$ڶbA,zX# 33 bXB33x Z\,`.;z`)I V6) FJF~""6ƴZWUUkMNtLulRߛ܇`0]H5I @9gڶ5ιm['Xo>jm{`~Vp|fIENDB`mldemos-0.4.3/MLDemos/icons/stats copy.png000066400000000000000000001150161172143270300203740ustar00rootroot00000000000000PNG  IHDRtvG pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F9IDATx[eir}kn.E&)5!J$1l`? 0z؞'˓_A a{eZ" &Rͮds{?"kuNʬ<՝}V#{:}]"q{} n6o6o =n=n=n =n =n6ogo_O0rix``&Dr?xp )" m^WJT->d Dvz.f𬁙3(l)x<d?Al8"zp B"z P+z۽;\^pS/ HfO:o3H0PG7t=~J$ș ˕~Nh{<vMBE Ÿ棞bfJ}H4X>#@HŹi˂>'z^=3BrʩԳpr}@p<0 A$,r-ao,-jV jg fܚ JI_~m%51AH砪G` %["(Ҹ_`K _4pa6ʛgܑ?oxYlV.` nf)9A (§#/] <%nX@ aP03²m +2,;_ѝ{zPm_h/Mo& !.ws # !l G+(} 70C @ZfC{hȞא!R /PyvIL`[tt -q6* v?u+~8HK "h1b3_s4r6og/yx "G/N 69`ɞRv[`;lдdcFw`0Cڽu`a[Q@ ѝB?:-%0v.*5Pau,`v{|R.DpCc70 LSUzFZk^EB>!Þo "3v9 Ø6oaV"3o Ʉ~m0zV0yzԈBLx{vw2Tʄ0'ͳ.y!Yn=oԬl6hSeC`B -nG?;4 ̚]ҺLl/K)5D5oxʏ^0u42q|0ɟ!cһCd<`95M`9:'cm/^_'KNc >?.ox}ECUە؂_摊uz7oQr؀fAx{|—~\ fCV!u##cZs;'=\O6CkssBzFOXDZ C &䯅6ö́; /UZ[H49<]Npk^˾Z D;^:y/#)cĘG4 WDGꆶm!"ȪhBKUAf)OnkfE/r~f ωf%3tvhW[ ~$$a*FĿ s^A'`~,UԔL6LTuPxKSJM B@Xˉ_O+-V=ٝ/ox*O@axfv4+N+nX,Z?Ae~xzra7(6sgw# *`QugTO䳿̈́Nje@l*I_ڏ bێ?!aAx{|Jp٩f&*+K]7x3 Tcvx]ܟ9'-~k˗khYOVdJ>m)KR H.vwkͰyoZtLHِ\GSe3'm&=?1}[ [:CtRNm#dH)*cƽ|2IyZ׬$fsDĖ![=-8Ɵۡ 얨V;AجD)aNu>ͽ_ MӀr`RbJ:P֓ovIdB*e"dLV3E-AsԞ59n3yhgQTp^KՌbuZ;T-:L&q\$\vqOL3B%@9`.gpʓWςmK p۝`V62f\ӫ)R_Ք,+"o`*oMX3܀(d/Lo53Q\.ܬ.: L9S{x%?r&VygADpvZV~ t{i~1宼aQ6Q^ºLo#70](CBp(D䌮:D!b붍⽖y}|>mm_;wwx2K@LxJ DUCnL]l wLĀqg?ݿxc(-/߹s-$78w82"8ryꮝ ^Wp?yo UX_oz+R*M:p?`%&ْH@XU m&8|->#83 VΊ6b(( 4b^`'C\_5\Щ~Zp2GA_:q8&H΢TϷAx_̑2;ǿ>O~\0% d >! ؠmӠ @`6isaXAMo$d<%p-   F #."R6u4df0# T(lSet@ma,g&,!Q̠EuFvà<@cj ?~ hrĊ~oFcI3CaMӴ+A'$N`V|8/*CC$%kC:6~ p*U^}*:3A0-H3309iG"ҪI:dS+ XD׼>"Ba%`T"z-k6~0$kfm>x{1޷9/g4P7=M]5{.qy?:\⽣lKh>R( F x뙀\\z vC 3`r Àeӂ ~tqۙ1c }n h+E"ˊ5w)sP&(1RtTjƲŧetI#HG磤 u5sԟ:tgcZ᷿xG[}#íiFc3 Ѩ5~t:+5ݻy+|ʻaۓ5#9fB̺6|8Ĩ_owA4H)a; ^"hM0mD374G[vج-䄿[_ǡ~8FK9JySmC%qmu `R&7ߎ&G\.ln/k_(Wyd116r;x_7O *}?MDqsr0=|<l4s!1{'{ʠ,UۉrBrE~P?QMۗ۶Ahlo~OGvRpf|[lz9Ak1 )A !"Iͱnqvzv3qİ]c9B8] ]$VQ\ƺ s)P|K@N1Q.\bN9auy?eaps8)@ F؝hty ؤwt F,efS 5qDޠ{f03\o>x60um{0OP%4P(}ׅ\Y#L8W:@ 3 (ɸ~SƯλ؁lp_@t8eQ.N_iĆ"c`f4AЀDp8v4)#;@0>тA`KNq,.WOWWJIܨnjd;0i_4QJyrAe=~z,L>?Ddgn=X?m@ 0]|D"'6PPfr!l53z@ =|N} 515M*wt"rlr,[w~_!+ ppˌB:Hu_H*l [  X tmk-lTpa a褅B[ʪk4mWVUN3 >YeVصe\.p(0RhΥVUqD-|T?5 !1ʙ@`//lChf (<<6O͟?p#":ɭ5Z;୳7|bwɽŝqim?rɚa>&:JXJlvD>LcEjPt *?K3i\La+;Y]!؋lpvkxV?P=X'?~㓏ǟ}|:?[c Я5!o޽uͻ;?<.i|ptLJ+<3cZl]A^`{*+qbTrҚ:k^³OLWL;WlF4Znvm†93k5B -aą-RN\i6o?<_)NOϱn#A19Xatvt=GUV ww~Ë7C2bHaiߞ—>}5kW[^.?GSf[rTJREK Yt3e*ar~ՈAAf$T}luQQz{/dcaM08VUt],p"F.hmѿ?#7x5Xw5B?*E|L T;0˅MZJⅉB^Y RiTʺ$W,^4pk&&Ok&܏'7}nM1-7%YFh.9 "YMiLC$ZwG?||o1ۡm~Z }?x$ޟџ"%{ R`^# !sfpesmQL.]}߯r·!u<[vќg2mU*6|~ 4GX.?ʃײ<>4ߍw;?;[D;3.h++NN b;'O^cĦ",c W꒦QTJp28e\@p$@!~ @z̼yZwgwue3/ Up ~;;~:2!Lטhw~-~6i|V*9 C>35b`K!O~}?m@SSP83'|ݣ8z [xX|L!ܑaԌH 35opvŘ$pt>)C- iqvr~s._k~{gO<+Z\gsL*v>->*_('" 2&3q.r!P^1R9 p*TA#!PdB\gv+z& dsqM.T[(Jj=C CΟ_Sz[߽ O7~{wÐ[0 NOOAnh"jX.hVpQ0!K@M_6[1 qZ)gBG.aC Ĉ1-T\<,$is}C*d-H4 VaAVEef463aȳcޚADc mۂpBT|Hgnw$-kZr|Yx6kYOï`дxhv]:!0w4!@Siu 2Q%ݠ!ɫG%`~*z”AA0Y`c怑d@XB*A:Эh}Ƣ7,>~W5cuxoƝG/?`xm^㣵?w;,4l.2gؐt 'Mo:$.\twK$]C" 3ARarC. ^lS3`'D0̻r*vk(|0*2J `W8*(Mu{+ү֬9IJr[ϩΪl׭) 乮k+3@IR5QªuT=w.54-邕S,O-,][mçmf:d%ㅔqkfg''ӓzۤ1% ճq@<<~~REJDx ؚb)-〭z zUX Qu_ ^)}^k]7WN(e5f Z6j>1<+c/kC~ t75ԃ3C lΓW7cUr8>W~_[o_<9;O٦h^zpM*o2i`- cd) ApFda,ACcO o׀r ]A]+(Xy(<?Ϣ[ 3k S/K7׮^?VDb/[90uolu; _}rzo|E_{Mbyv9Z6吒©ClD rP065Ex2 jGH)C?:9M.!Q)sewq8pU0N̹R .+Fyf *󢯍oWTe&֪;L^btWQe%i>e < X:1-y HO}|͏O6}㓳v*=: b|xxW8N>EVoCӵGXcqx[6y{('pwkG4ghRxG@deT;^k^J 7sYA0_RK;+Sj;>*y&% Cj@ʬGN{^~z+oSsCJDD& RXkL#n$ n 07+vVB>22<+DGle,59H%O.4iL; !LBtޟRZz?^mBg(9:ݣ_yO˔D3:磽TF !T?9:2X% c;Xg>9œ]ڀ0 Y&AAŐV=J!A`SU!Y|AVx 2bS.D }̟3~:hxE->O](b(DJu gգ]./\]&s9Bs]63hm:ahnFU"˧:fl|ªّr*`UgV{CV78Ӄ8R饭ECڊ ͨOsfl*.(Kh+(त~]btP®"`Km^{朡3=aۥjHULu_V)SޱO 'z.QN'5A7i?Wvc/Ǭ30W 9[gs?nV'pƇNٷPMXK,m3 Ɂ!oHP(+6i &bupONp1c ƬXR8#s pqZ =~e`4'FG y#gEqA\AKǰ`yt VBK':U꜋Ka7s$5c91ó͈NhJonTt>Q!G 4OQv $!mݢAd{%Gf(v ^J=ҹg^¦[K#RNARf]/.'-iEC}pØ̉oN5Y&aaeP ͢ 9\|YDt]K<9۠_4H-%cX"-6n\l6P-fB(EX\=͑]1 Ǣmr1ƅ)"ع1;)ɹZGͭیV5}6˨|)uȽN9TgnC4߀;W-;kY8g;tbU}."\If LaHZfxlz`Q,i8c yQ,!YZ3<`YJK'^yz7z5];'Zz˺C=yPC(w(¯75#J?<՛j["WpR'k`fT',MXp"Md9s据$G!h:~ov~+yL-{0>& *0r2ʆFG3#0\]jbu+#U_A} ~\h l @"2^5_uAn"X Y#t`h'$a8VblS 0B̈]&"`)#k8`9 ^- tV)bb`H<& {(뚆zbh&|*P*qsڣ,}UyFaiۋ}&ĖJ TP3)V* ߐoaE I@8(7,D4/ǘtF'f |&M`i|4rt?$%\M+9qF;G=6m@kEh = 8n ;&}=tGc-$秄IdY1{B& +# ɍj vd Oh&N!' \VYΪ{\.,~^Q]3NxV֏[HL9K8)= lkUxp*,X=\lqr~}0S躬n+H$X6 U4J@dB Z^^A:tq 4|l ˾,K3}lOCt-+\%p_~^7C'r;&UC.ioj 4<5io3ԅ1S.\̾gs=!`f\M%Ô*:EJb`_Ș:6_F{G)4MhѶs>ɡ]8Mp|a֛Kж  tM dC?$Xp]|2 ѯo. 4hfL p#UBf 14Aq-BE'18k;.$DPOdvPqv_!bT_KZa1ޟaZ!>}5пEѓ4Oj}Ò`O] 4Kk.,m9+[?c}a?1eɤʪÐZ3[{DfF-iBN˹ތ7 :ys^9c9ߋDt/;"6q|o46~X|'ÿN1@4@) 0|21bD mł1,Zfk.}ʹ[hý[SJHi@2y\%@;VF/ϣj3 ) Y/1qi!!5ov<{ +8166ʬ񦃐p1.$yp lاᘈF(Wzn̴1C5͇yl+<䔏 0b+$eD3l4TA6 {|p2Cr$T}O}!5 XR҇eJAe;_ *cz>niZ qY&uU3dPWr3zO#|K3kUuv mx/qjQW&:X j\pFlSƚfBfM8-fk&eݼr9ڶ'sc)2hڏyd'Rzc i|]%~c G"UfHx-GPqU=&VsAʲTCOe4U+}I c4GB1! Ck,wW[x y0<=9vyuq'^vb3yv/|wKU@f-:'[LKu.3enG/1Ls*,kf, )1u%(͆3t7?dtmJN,zYSՅ<6!8yV@习TE7 0NQ$(1'fҫA XuK!¸2ɰtv0\lga3“'OsAض]YBbb6aMCY3Ϣڗ^X{rn4p ĊyƐ~ j(CV]!93- ._ݿo"@fX9̌"x%%(͆NpP9H-/A<=!]ҋ>g;L)9٘bX-w-4S0oql\ .XOHi0=7{u"Dk2ޝXq2{<:@^pohhs;+ b !ڃ%T7ϱ+>'I?m{B,t\$faJXC(hۏydb+w"d=%Xݣk^ED6Wk0NL̊ypIa @2CҶX,Z0 ht@{x+oΝ; xMq^8:#[EIWڥ!zIk2\.o|2 JP2 }LheZ1,[0i W$C4ruG^djd0C$C4 9Hv72=8s ׅ@DC ~qw9f6d|9Ypf/IJz Z0.q{01F 5 F:o8Z%!$\#pSŤQDuXkŃ4:HPe5WkA0 d?rH#aKI3jG 2G$Ey@JhRO@_^gyG! 8^}7~Dq\׌Tf,C',7YRJx%Qo ޒ.!i>(ZƢgj9_Esn+#f):?L}i]4a^Kȱ5F6`ݔ9T9 owvR.W k4@^r1Mqoh nE B)g.i~:/'#33 XADf'M9͂'ˌ*^wzB/DDaSYZj%"qbm" 36hEh?6&9A!^JR>L&g* b # iJS/HR|U0*2ԴRJ"^-CwJЀbSF-WlG-Au6=uE>h4R52^/y:_^3N&$w#:YT׎ Hjo|9c]G"2*ޞlw9+@ݝ޸#Y2n_v.p̃ " J̹8,b͆G5IK;^])k*S ZK2qDE l;[|[UFwU+ ~' 01K&k/廊0 mnh#)lX.;$Sڢ>ש2 pNAU)6*D[_P =# <9a6[* 97t%!oAeIA,t ui95B8AVX9ŝ*cVϚ"#df0bfG]Svȥ,ċYF`qއ1c FĜ  <^me{mO7;*x~'Ux2պ=An9 N_c&_s'0fz!5+Z8n;Gm&͇4WMHu+[(nV(Ax;0M3,uO"(Qʦ+(dm‡-p8_׿~^vZv{‰1v)qzY6i1t.)NO):^QոW!HNL Ki8NIbckgo/6]󣚥sg9wd՞1[ $s2nRߣjOrn&*g(RU9u6D\HExc'm\"ˆYzH1|,A.]Z3toϏ.4MK@ι cFs'ĊޭwݢŲyx7vFhp|| 6SVvqث,CY֑ jsOӝ)qDfȺڹB*sBug-7?Sx"#I)\IxK[3,3=y;%"-g3Tl/Y*jdHIRNK6LMiT;+Yl$ajfQa"mO[ݹk85u~WmW8ݔk) e=_@x+"֘Yg9[|#2ia|lj ui$)33=LD< @UaԌqHXh:w: _*?9A=b4 *{8$) JZ3'kr,**javjsJ~E=5q#<ЧL(eSa-S.?ӅU3NR>4Dh wfֳUa̛4']}@D:\WDW jvl﹉y~Ax}~G9YH)Qv]Cfi[k0.Lغ;3&1;д1GNO o50y,b9 &˃Փq/o"BeȻe' =Ռ M^-8S0 l AA d Vw1t* WVЉdMh'9;|oBkg]4fU[KR=Tx]C71l&~.'5Ma`tm !$2F;rd*E=3Jpx 5k37sEkegϞS- No]!Yjm3#ܣ g9]K8t 4NhLfJ ڈ3 `"̣S|hfXHxVT!&B:!dSdPMCSR uÅ3nB\9s*um0+!U/eNw8?-u\§ ,vf-NtL)TI[sڢjlfhE01>aߏW ]}4l9P,b:* 'y:S΃_s 0הRyG<k9 39;f4] Xn  ;[B< hy8SS +`R`c#JX74PKɔ0Zm[xn5 8 &Sjq(+܇=#GqZbe).eDR'fli^eM 8엩nە@ [4t|ulmۃ~dG!Fik͌ XUFKCs`H#2+ԁ +O~᝻ǿf<8 5&9 }3pc|BLej}\.ߛ/: mMSN_&>æiw...4M WT;c%(y o6h8!(ܭQQKs p㠬$J'A@@6 OД'`'@ZpH-KBPEw rmvN:Ţ4s*t8*W{ ,6 eq[YđvMÎ@T 1Յ\w'j>ۤYTފ2F2'.T6 ,Yp^v,/dUDmw'(3a4*8W3gL~ $14M(pjf0 ̬i擦i8abQ#"õDdϽr[pF"ҩR7g8QfXh%CN\Um,^TLIW7Dٙ0z,!.51O8Y AӬtL A'";(߬,9hZt]C4cƽdXoz8ߎ섖-1Y\{VfC=@3h+``枙u UZ"Z I,+z7]KZEaNϰs)" Gwqxx" Q!Ųs7j-hSptwS厀*+̩ nlX(xRsUo풳ؐs>4פ=)q+O &0f~*gJP`Eͪ9jϷv ̜b')օ洖Q eϣ'y6Ǵ28O7v){8 3LyPbLX)Pݙy?՝d;l!o׽gçM9uX!$Sr_`D-f|R) RNaZJY\FE5wXS0-;4`ioqrz<>x1V -[%Rƛ[==# McT*F5[NÒ;/܎IsRm Ħi@w@DZnYvPa>l.~+ diAN7 ʮ.M -C(FQ9ƴ $16+phA6QũZ X$ӧf{Q?Mf5vyd(wZz3;So%yZB1O=+Z wEQ1Z/уHKFLmfٹ7&4)εW\/eQ`̬^ȋV\U:Ќݻ/3r·fTE%b˩T JEctq1W77S1Mu]$e1<\B8軶yuݷDd鷿xp=wl 3k{8BSCܗ"`pP I(:);鹚/MeUr6GFcݜhi\`ѵ8:8ħg lC hap_W@Ni 8Cߣ F Hc)C+]ѯ7&*mЇ9iyݒEdl@ V› EHyj"B?ljuAM poPw. sӄ.MOjSJoȓbbaޚ0bd;/3gNV/T9i#jEq\8=*PQū١+T'=Ni0s <c|x\1laHDNݼ]J/7 O6 ðLދ4n] r%MNW%6QO3g 8~܂ ]׉UAUSAB!jBh" e>*AT;݁* MeZ2jjW7xKkfhrX< ؞4[ M4N9nS{mڊ+cf:3gl?ݞR݈֓*4U& љM wf(|T TYVs>;T.Dƫ4~/W%.*nmBU_Pu:]}L ܙF#hmߧ@gIZ (u`x.v1rj y-9 lt'crF~ {\ꜩ<NU8BPfNmn;fVS'"`~6@ \7zD~ǜYϪ Qbk#twL$X/o Ӧi= ታc~6[*vlH`*m?rHcVǷi Ysß?Zw*v6TuT8ԌUttB+O1 cVN7c#{@׶1(e1a&*kˀƮ%.(i$͖x4^eUD4q?BNK(r gDo_SbFM+lp93o;/ /HdzkNػl#0֑bR$O)"bƄSsuQd!Ϙysr Czh$v&9 yDNq|owOmn4$|lR2[;r0<ːf.jB^ȩWʆ<1zs[1-T:ݜZҴ*,(kGM|whxq1BaCd\X:÷B7d- ]7qZ QJ4!Xkvdbf[7#SmjЕ$2P b̵sr ՉTRՏq|i>!WeaUud2UU\QT707]|Ilؼɬ|"NZʎ]B4.SJw8oOBE 'u8irdQn$ܯ_ r{tLo/^$9|EUՂx,k7kiH+E@C9*V9@D̼6iO's>) ,#40{VU'U)dWF,Y58 ˋ N/^cװ#hWxK ;qJ(1=:=@"rB8}3jEf Lvb72f/A)l_3@&IƕQi)OGDy\1yoXi nӘ""gDA+b3K~"zCf0pc҇N8P +Dd)WdvGW k9yuEYS`4ȉA[l6M%'/p g)DֵTගX,8^,!VK,b8`AB1uP!93^JGx)%)j g3[*\ɪά٭Q3kşIAl-̬4W%"N i*EWtpn,"#Pn&W8vedf#^UϼXoB8mr]" T>\RasrnH@\. MM9\o4F4Գ7_?8X-K?to0{kDZX߶ [I!6DsLT"r%x|qqT uO0qR4Ir~LIqXm8F`E-Ѓ2!+Hw0`cnqZVXĈTKڀ -M nu4Ǖ\즁{UTDٟj%C3%AqE3\B -)2mwҋ|Ih,ÔYC}u;cvMsfR5LЯNwU#$G,YUۯ"'6LhޭI|' mÇ]}wX 6YYd%l)p1ݣ_r}03"ښ"jX,>$ɓӿw~Ν;;l  DޢaT;곾5|Hy擤^s-A%z$w|{z?|Rz+e mGfv9e:#@K-UFLPF›x >S\3Vڣz )lâh64Ոb<>y|ұdPY*Ƨ0*O!4И!JiPl!7k0KX+|oVퟖ%e7Rs· qLoM Ym}~ ly j3/s3p2%"!g`b՝8bffW9)rښ?}fKi7vѽofv}7os~3Y-A茉/$u6?l~EB8Q"ɓKD&~!V}@h?%303 Ãqߎ1> yX,Kj_UՃo>ol6<;;vC#w;(߬_ dMJ8|wZń.M3ph˹!rfqk˃?S8︻4MQ4Lrn-zroiқذ..0m>w2ۡ>f{f拮kfK3[M:!dJ9Սa{2Ts,n);#c=٨jSrz...~c~qX|92tT=O6M<oၹ+13sUq|Z Cf2ۚ^ZzJv#Q&P>HX0WTuŁWc@DC`YX7!>sح3JC}[ %r= 3dr!`٭JFs^-ZD)R+W;B5\Hp힘v$MYUs7*;3);r*AlZ{rsY-L_mJ`=O绸V D5=mN\e.l<$=ޡ8oVY>8v:/{C:hx5MPB)1ms·!;3kjGuys>i`ƺ!|Pm|Rz[9;%Ireɻfҡ;cYz%fg[;#@=b)em1wQ?8+zckB#8#Ґbbu 7Efb@ {'<}G]*Cs,M6r@lY}mT3_{2c!,4!XQDfŒ2"^t4 8Oπ`D`M@F:S* xjƵF9DA@,[YLF? URZNv8R=޿ UTu_Of84U2_cwj\A)9vٻDnVUN"@L-vwgJ?u`R<"BrPWW'Č[%Ql+0 ,RQ Dc HʤUq<I""\@530TY9*-6az@*@Tv$L(?5af^;[FeT"0V( X%(*iQ1Z@D4Yh LsQ\5H*i"*KbkQRU"qD޽ !\2cy~4M;Zp-;i%MHPC|`bs\Nt?N?$jXUC|ht]qMꟜs9i>><m,۝NWM"dU"yiBQ2i?~4]4E~2q0(!(hP\N/#֝{nˢv-3N,wRq z1RDVE4`sTJ%H$62+c<oШJ H# G@]lzWȥg%Bz^ZҦXT Y12@4 &Aocނ"hK7L\tO4 {yQ#n)g‰m2mjUT(!){EP߻l}1g5f" @[,q]>$/ᲖGzJ(Cť> !|`?rj+SǾ! ,",8Rr^'4}r~eNQN/,2@EY<.4]]Vc7XT[Li~7pOCιbiWD4JPWM]5V 5b,,) i8:gBHM<-Z5Dj~إ/;(\ !K2m/r'ιVԯAnl+O `oRc^XjŘwG!9s'Il fqXPdNDdN/Ȁ0?T+ļ9P0-{s310 lc9u]/k2wդvUbcч4'⧋"a A| }ŽJ:c\9HR 8ZEmT$h WsL5b l#&ƅJ\)5e?A3<\2yށL;8q/݇d9BsZWEoY^B,Bͥi53BxBxvQ~?uW8H`#i2Z{c2{Wpѩ65@(cva2 wqJ^!bB01 gDw~8?q}\*kUsUvd f meβSF0󆈦IDV_ֲW:~O??_r?HI("dM5]353oc_iJ@@_Zb]9"A5%~.tH] N=q3m= OƼ=_޹81N I`fg3HEe}2b|Q~~}uM`x>tRz*9ZGkȽ."Ȳ]Iг_Oq|F2|EK)=s!N![ T"̮` CmhyR"1b_;ºqQLr$ W!5&Pwnsz9wԛY,g"zB޽t}&t@R]und$C(Wp{"x&'xf yDP2R+9. yKiiɆF pZÃ%-2"/=ng<Ԏo@eDt\FM;޿hXwUuvFhNeH{cRQH9A)/y:;;XD4MRJ< `Q+o6i]m8鸩X8?6ڌn3۷z"rWn8A& pF#.l@``*8*W'&`SʏԀهW?;JL =E0 f9独9#%f]ɆII1Ŷ(i| 9{B9f1x p^ 7nv0NR+ ĥD2ft82X X-pzUtS̞i??e~ `e~[oI4 B(9>թ MNz;fwbj >7E%B-iaj꧕7PQ5\_͢ =e^K(6pz3i?^.O~wzz.qT̈bHs5B!@!009\]'\\\—1Ƨ̼HvNr:w^e}{Qb&T|x2ig./3㬲N)]/r/V'03W-SrIPs]@fXLxTb9ߓ R&xrL@웳»㽇{T68=]$xja4CzVB%EGT7?9pa1NS`hsG=[[2;!YsZ랙' ))WD-92ă`GeCƦZ]8.vdS1|y;M*J _f, #D5HuE{3~^Ed޿b揉h?A 0 {G&F(+f )EEH-ySUwԽVucm1 qrX}$d>ǀ_nt5Z\Fp~z'q1 ʧCHуwc>_Ld8$ۥ4xEt#:ctxcPy asQUUWtJol[E1!,w [*KHYUQR4GIӒ_.򥑙̲xYL&22aX:λGm=,P(eQelCQ~<̼޿S /ښL H'Aom&&Cp_.Obv݇!'˓ORJqO=vyM"3 xY&m@qz?{5 g8gC/[F4.8 "g)fUo=Xϧ`'@tf"βH5( 2zDHqIT 6`W^mfÔPA"~H$Xa'C"'v݋`Iω2 Z'fE 6N³g޻Mys^3MLk ȢZ QUR6T-aB@щ nM+AGsI0T:\ms绾xI-VkTu0lT#xTji̻ ;:UNi~ne]~d[wJ1"Ά 8&T>9h"8йc@gC ͌nF4EERER9Qհ.0Nh('d4Řy~9fi,E> !8*/#n~hqi*s݁< ]2;TȾm3]cvһ>( A/RPb;\գbm~uԦpj$"".w9=rGǧyXDo}}Mp1yf"08ŲHTAT#!f5#EyT|UMh;CRd 1MQ HJ+8EmD9{w-kVF6;Djv[x¹4 av!4Cli0ܵaS_W"#br9t[(z pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F7IDATx}{xT{&`Z!@ AAhS޾^񵟚VMSmPVWPH&A63IU V3c9>v\3&M&0; ,V` L+D -AA8P %&Ra90PVVʊ TUV cA0*% n 7 ~hw7ً".hr ^ B B*HÇq1Ǡ x?B`2Kj'hq@h?Hp8 a@ z{zПH -سg|*Q B BLws#GI'bذa(++C"@"@(t6TLv<б@HyC& Ýh$AI O>=^!=fkjKXu^pܱbر(GG(XX ,n d,8# ^شy3X| VAXxv-b=y Jx.1ϲ `0y+ @H~X8tw`hko+7#fW B Len@2ణFZd G.sH>u䁐 Y`P||0ZӋ^[.xm;jjehPK?1PYYr$qƆؠsQ6NWz '4u3Յޞ^l|Uoc Vkjzs4g&QPQQaA''aAxO&]d`H{w;ȣ"s2;]F>8x`vT~Tc184b@Ā$ b[qÝ#4_݄GWĿo]pU:;n0!@@XҏR!yeA6  4 ĺ{~z<,fدAAx*ꦜ&'r=XT!  eWpg'rJ/{|Z Ce~d2StH_ŧ2ǥDTNȫH|1wv{xOXFhIa2J N=U$H1PU@JEHXqtuaKK+/_X,F~xɊ4-.M9e2JKG: %!P*MI>0y> @JE8FwO/ZlW IH櫾b=0bp9Tc< ӎ} TH$֭_ :@2?ۡAX\ lĄ \dЗC0XT", wՍx]nDF@;$w:ߧ3 V3_P([U"lEa`(b"\r‚;EKK n:05.x: 55Ic,P0|,CbL:zPE&X#B( La޽?ONsܭA8@X%ǥqPUUԎYf:#ˆF80LhpVFzj l3tk (Y3OǠA\P^ (y,(rEd$Vv*B*cmJ¦M@><$w |ϓuynӂ-6&y&a3fںrܪ%y|`QDqf͛o}~!l aÆa̙& < 9F$, bx衇Y NwfoXa1bU~@Tx x 8XA}*E<T Ƚ\WM=܃ &O0ϽaĀ+I֝r 3*~FJwH@<fsE 81$( 7 v,2:H@뮻pӌ8_06\,HU: xlEO], aQuEyc0#؈;|OZ ̱U ȏ\.(kQ#EւLdS]^'KE,1,@iᮻBuv\ !H&*iSI ǀ"ʂ2 R, ]a B"ˆvEqC9,b2ȊӧO=wÇ:\C4scπ9sɀiH*b (0BҌU;!;}j)|B8gaҥSǙkC0;g>,ȋTfUF? =,P )Lxxu!TWNUB2e ~v=6׈a!f~> А @,zɌa,P2BERݷm*W(TaAbHļVS?!UZ ̰M0X]A5 c1@1d@/"õq8ł)N0 ~*ۚ?7%M[:%-OB!1k&W\3oyԨQ?nMEN5$aTBݶuVxѣ1餓P[[ ?_3UsCx : ݵ8s6t5P  cΪ'rlvA" xoDIb 3Xx֗e|s7f K jB=ԃz2,ى-[@n ^ `aZ_Coee g_60,1%jo:;þ)L PdMj>ccm_4eH% @dj CI}rQ MkpmB!466bQ'cŊs۶m{عk?fאhr~Yǹkx5cr\~٥3ZQ :#1.")-`wŢ'hzTZZ+VK.ٳݬ bѢEIJeqwyWCi ౑I,%T*n(B _G>|4f9 beuP1SU=-f^`/L 1o<>:u'h6R^H0JϲSQVEXEyf͜\cn;ĄܓN<-a 1٩V_EGD{oOU,Y$BxChHLV0"޺HBUDI4h1c '9PblDžboi߮[ZZD(d7n1c?/4Sv)cf``ˍ([5!O2 " ([eӱ#Fj1&PÈrx*@#bW,B &"?{4 [-O;T:[ի1`׸2?zݿ%#G,1#bDW*RN favyyr1si&Ck`:d(3Fπ0yBJEU7| @kcX bw5מ! 55)$w:Q۷NR:z=łz'8Xp̵w(B2$l? y0Eپ&mmj,XlC, *)aJ;U&iE<1ƃ,p ƆCdU3i\bO tI#VFԩunfDk+`(qrZ)P$>h63vD0Xp&L^b=$-#kHկYP䆒 R25Iiօ;qātUXLt2gV]][^Vʊr68v*"[Y0l)LƗe{!Iǖ/_n/̲1cpܹ.(eg?R /1wEYYDC vQNPwAy102F3aHN>( |illL;6looGcc}JEd ?L&p-1Xbj]FS1䓝.N䁐Meg 2L^e<ؾ<+&GLh78Uc@ezhg"!ÏGY$vĜN>GQdVC eł~b@f:y샘>m ™$Q= *Pvr}Gx]M0C;Uxe>š0=BUEzkRB2/xgGÓL*Y*0e=LahV 0;v@,;bo{Q[? MjaݣÜaQoĉ'$5K‚ڙ 'u{‘܌VtwwUVVbҥ꫔rzĈl{aA@S,)K/| ;@ 9LS@t0U @ٽ=Z-6U~gkyhg@Qw "jNEo`ksbnm}}} uV}x3*8; 7VBe"~YD~ZIaPYY2q8FiԆ1X6ֱ}B$Gŋ/{1,X ms<7><gU$6R뭲F޽{aI: Ԅ,G"pbdeixySp$g}YG/RxŋQSS}En&|뭷A(l=#'䊞[I^cArX 7\=ףsLXFv * ޚ=E-) /IK_es&?m?~;̝(dC;^!dL5W[Fсfohgɀ :26y纠<guux1wy fC;yKvzeA%]e͋vzeahzڸVѝz0d݁WX,bB՝*a\S-/^~Rug0^,\?TX8o\3]Y;>è`*>q,ń"Wu 5p{IEeeA;JOȹ+c7r2.FqklV.clWڙхu_&qe E2vƳgH؏Shѱ};s_׿^"D9c@UFP&b*!eyh'ϭlMRJEIn|]Vb?!aen(KxaVMYӕ-^D^QȳvЗsyqm_{㫯'(C;YL(KQٷ35J־c"L([%-C;,(1 % ⭷PPz3SUWT);aڙIN*E"cX yF, T=ɈX۴ƀ(%(2hQA+J@V \!f &3Ă$G4ddK/ 'ԔӶDŽ|0.X&Tw̵yH 0Ϭ[X0X0iuPGÂ$21.Ve?Aɪ_%007X( |"0r> ⡇vԃWjВP3t7سŁ[Ԋ F{zwVSsMR _Z7^~e (0(rRM liiϢ5 R=SW1j8 *xpuGww'NcvfK$GM= Ҹ7 1uӭ W ugǎ2, RZEd|zJy VW]}5z+&cyj~*Y50MkO8;UDuŸV2NaYNO>ދSO= 2 xŗ/^уp!477KiTqh-I / h4mۘkP_a'Ƣ tڙvI/97|3ZZ[]Yd -[уtR466\N4vZl VC;UV` n2`H$9`.'2dn6>}:#u(t-vQ3Ge L7$gƍXx1}]&SY?dg6lڵhjjBSS#%}89hJ>fQ[a47A{$賍B!l7^ W_uf<=oT&T(*'eB1AӋٳǡ~.Y_|q^~!-[e˖9e8! /E dMiǕ [(4 ܹ6wr'*)ǻ_=TW&vf|AhjjK/7K.E[[Coreh+LxcN74ask5wDŽcx(LE4/c~SSS^G[0DSS/vvvbSNY[ fWkѺjjlQN̂^vgFY0Ē%KY#b?\2/n!H2r xºuf;OC;H7oظqjdZVJè~\OH o8OkMcwX7^ybbKv{eh(R{5Aȶ7̺_ XLވ(C;#qaG8cԎ{šb̖--_ 92A?b=<"]]Pr5(ʮ:~xŊ^Pyc*LK-^\QxORlqC`_>|'^smAPn|ۺʕeJDSX+ $X G\|9ؑHGSSYgֳUg?" e. Dcz͵UPVHz=+^BeU/ZyH%.A`e DT|m=|^~Nii&n~ o<M +TTM(ih -[RO_aYJK/ܹ%%~QaJ 佞x<diKk+nvsgƅ6 *Xٞo94B8Ags0>J3,%UW'erhEPͪ9%::,_v?0`!CpΜ9 Nfsh(K#Z_v:Co#m pO~SO;UPG( # \Z l޽hmm{r1l): *ؽ{R>>x?y]w80)eX0E$`^\dieh8q"~]QU͵ rkZ["r2`,'jk|+Wl4L-RC;\a=D(Y ƺ3\# ̮˺sh."]Qgh+*d4P^y#bA&aV HՅ1e6A}G}~P2,Hjrɋ ա ƀFcxn.{5a<@WWl޼9saJ[ Xe!P`k* C;TODAuu6|Ck{ . B 9Krٵ -͠YEBwVeޡ-߸JC;EEnJ7y+A'aVo;ǴY~M>b@fɝ#bA&C;E u69xA_$#zb * \P[pC;UdvhlWĖaDo~7ofыr*SQ髼"qeR26S؟-|@b%SLg!a,v @ e ,P],&m/E٢cB?'gwOرk j.6Y| 碢"%0!I`fDvIs=+aHA ŒQYc"]UAL`fXP@Jcb8i3k! , }ahNp:^O?I0BܤXPJ*!KExa"$g,g׶?( B0v#g̸hB3z4Bcn(o*Bef 'n|?&x>7aR j'.̜5 e{u?y5)pgF ::i6w#AX8vU73'=X=\ PPc""f pgA%vEсnBe@?g"XzYs΁a('xf*kQv&0?;;k.yɔ_kMB:$wk30yr-+pϓS `_ H -xQBYC;Raۋ;c)_"YQl'Zp`UX{AyYu&Fb۠L ;cv*BΰV|0 g{ߏx.b4 eUf8E}ј:e 2q'#y1b=h 06^ٳo6>LSHn] z(T kef8YV9N`UUUBɠ*~0D](8~~;wDOnD".ho x &)[&6!mkL@@JR-3l!Y^>5ɘ# p8  8cL #aup" ԦMhӦAM6m4i ԦM6mڴi ԦMP6mڴijӦMP6 BmڴijӦAM6 Bm4iӦAM6m4i ԦM6mڴi˼HChIENDB`mldemos-0.4.3/MLDemos/icons/trajectory.png000066400000000000000000000065461172143270300205000ustar00rootroot00000000000000PNG  IHDR((m pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATx_d[Q?YPJcPF aFaPJi1ce1By*#ڞfJV2g/oǹMGs~9Ir9y\cGf`9όgxt$$Oi4iGe׀j'ZE~jPZA-o s`[}Ttm~y,ew$f̱)ylhؘ#6[ veЖ쩱ⱞ b%x&wR+gUcsF@v5)Ds5ej}-쮉vg,$Dјvl ;䱝y #c%*~ 8*3l7.%P{ɾ'=jJ%<k})jVIKͭ5iL J,S=SڧKDryci*u@(E{σ{l_9LqV.U=ˡM2{Rɩ4:XJtʵλAZ,GQiJ\s\R9~?03 0/g~IENDB`mldemos-0.4.3/MLDemos/icons/zoom.png000066400000000000000000000010371172143270300172640ustar00rootroot00000000000000PNG  IHDR((mtEXtSoftwareAdobe ImageReadyqe<IDATxQGQg"")e%7DK}Kl"2it.rݹ+,۳s9eY೦U{@Iv؊~c Y68&U@bRn!9uo6 $A{8+u nk ,.H+u@[6YD ֘f'@U'`mNZ w8^83".{ ynYRQldw*_~.bNdσp}Qְ *'X%2yo'_&1"bN3)BEB>rHO3lPBN Pܣ׊b]ANPyr@h/R>LVYV[} 0IENDB`mldemos-0.4.3/MLDemos/inputDimensions.ui000066400000000000000000000076251172143270300202170ustar00rootroot00000000000000 InputDimensions 0 0 355 320 Input Dimensions QAbstractItemView::MultiSelection Unused: 0 Used: 0 0 0 10 Randomly select samples Randomize true true 0 0 70 16777215 9 4 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 10 Invert 10 Clear mldemos-0.4.3/MLDemos/logo.icns000066400000000000000000002205341172143270300163020ustar00rootroot00000000000000icns!\is32m|1Ն r_}@p ˂ˁơ>!}qn~E{ɛ%ta"HWr_Wp7 ?,(^&5a :q 2ɛ%ta"HWr_Wp7 ?,(^&5a :q 2ɛ%tas8mk%&))))&%il32ɂZY  :DPoB7*B9Ľ,5uzkTڻ$ZzفmI ;, ބ-R(E[M| |[M.SEۃ ;7, ZzmI%wzkUF9,6ׄ:DQB7*I{|J ]~   6 5I7*) ,5  dkT   mIW<, ބv(E&M|+ |M]`FgE 7, KmI ;  OkU(,6ׄ 7|B7* E||J ]~   6 5I7*) ,5  dkT   mIW<, ބv(E&M|+ |M]`FgE 7, KmI ;  OkU(,6ׄ 7|B7* E||J ]~l8mkRأR$$SSآSS%% O١Pih32 I<[mrrm[</@ӑH! y }k }u ێb 4 &q܌^p_R9ɦľ* ւہ 1x hi> M] v{⺅_ojSލӕ3Cχ5쯔эƔ</\Ko`sƇjsڅjo`\K</їڿ3C5ފw{ØƊ jS  /x hm;ׇ ~T9āa* qۡ_ٗq^5& uc xמ h .CÁ4"H-K_jj_K-n78   !" ik }  Tb "&l^ $ _* ] hi>{M] Ņ_ojS ߇5Vٔ8/ aK ,c`ZBj#j` >K/!ˍ 5 ԊjS) hm; -~ԁa* !_^\& c & h  #Á4"-K_jj_K-n78   !" ik }  Tb "&l^ $ _* ] hi>{M] Ņ_ojS ߇5Vٔ8/ aK ,c`ZBj#j` >K/!ˍ 5 ԊjS) hm; -~ԁa* !_^\& c & h  #Á4"-K_jj_K-n7h8mk TȘT hhyyIIcciiMM|| qqUUȖUUqq }}NNiiiiKKzz p OȘOit32)6'# Mbs~~sbM #' ~  k ͏k  ~ y y% n H   / 6v  J.g$   B+Y R@ kB .l" `2r7+Vy-0,ot - |2Ha+(  $+),ԧ)&#mV)45VH܎U_vc pv1qCI*$mAoz x-m!T ,B`  ˨&$pIS"' Ǩi1>їo!*:EX ޫG !A5k ߫) Wwz{N2  ?  Ml3ʿCCx˰K,ؿ + "P Mfg'dZq<tz[iP"@ldWdH~4s vq"zbP'T)iHpzLm%s\q%ret7Pd+<M+'"F S   i*xl[C O  % PwnNf P Ik!L Y zxX^!V3ե2_U+ Ȝ vpiJIL' ˜ Am6Dxd" #!W 7n-o$ґD{j"$,r(o51燱Vft4vTnFԫ=7$:-nK %Hf . '(tVOU0 7'y,rD1g# mb,f  Dd- K) %  07P   XE U  j k  ? ͇?  2 CsϦtC 4)  'JJEE%%==$%QQ  QQ 89??HH;;+QF?ʃ?I͐IGjѾjGic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP m߂ fî,uq[>4 Ū8|&p=P?vIA@/UO6߂0)r;*i[Z"vH:;S?h q,˫;YtB* M7eT>߂0)r;*i[Z"vH:;S?h q,˫;YtB* M7eT>߂(.nFeA bS{j렦 5@o_\AhZ#ߚ7s7'WؤZFu݋ OXmbv@uoG D!Vkxڬ_#]M.px:x"$=xo]7)_ i '}ס[W]\{P[sw;B ?^{=*!8+n::"j`}N3ߚ O7sMLl^]zâvDfF1\(~vѰWiUc4(ri`9EŇ]Nf?ʧ4NqToNP#c234x9"HSu+d#?,E,'J!mfl}e?p*G˭o ~}ϻ) 8_ΐn*&$.(p|pZJo p UCLdc_ԧ6C>;2J&팯 &\R ݏ]_lD:32i:+P2jF]Rzg иytg]*>潘DyJYca|Q kZ}Q[%XUӏPQCE4hD.HiL jQcSNj!2b:sYpT}Z^Jl*>sn s\dg_lD:32i:+P2jF]Rzg иytg]*>潘DyJYca|Q kZ}Q[%XUӏPQCE4hD.HiL jQcSNj!2b:sYpT}Z^Jl*>sn s\dg^kUgaJ3f^$y{^z1dl%pbVH=<:z`Bna?W3j(^R*7@7c0(!Y}UQKyKvJus4>'!AT2F)mTP1 zZjDX_xj% sw[/XpK-l)opـy7d1r eM]%ϕ΃R~*ͷ^[pWȵxj|oĸlS񻉇 < r>ϧH{3_?ܼAWCn 2^KJ(V?<-ufOl6! XݮvX&Ƞɡ\(R@4u Xz ,Qmqc9qC<^PC552r'㥱+/ X; ] p7Z?@wG<*Dh3_lԿ,wc.x,)DW3MÖTӝeV eIQ ۟H]eٝۼr[{SuGsI ugM)r4*_hvufVܚ:c4D7?^ATL %v-KքNvL`39m/BQ߭fk5 xU+" hmwO_G7-DE@l 6bJ}lcc'UI)YGR+WdOah9+3evjߞߞGᲠ][^L9%X{.9sW=nP ب[>92 UlWRb<"o$@lP>{8d;=IlԟB'.JYiU5Qʳx㥤0ܽ9WbẌ́|N 3}}U6WWLF֯0 #м@'֠T%B񁹻Rϕ!QDt#xVù-ݫS/9dys0c _ڴ?Ul궤td(c\ql\>)K6'n']O=RwmL鷓'J>n2:fBeCsFчRqf/0$Q0O,Li_ -ג^Et 9um X|Jyu] o$?%Cډ4/Ay4O di>ԯ˦<}Z:+t2*~eUVH1o cG3bV;0Cph0FP4Mo2x>tq&F'Uu'>ա+σ5ATGzV"k?bicfs]$ʉ3?nDyBM6{7][xqoM C]FNMu-y 8 (ӑ$~Z.E:"yr]p,V?q-хb$7-cpQ}YWj[ذOK5a'Nvtqlc Ψ=VzUp JZ^qˠL1 C봨>2yQ{Wp!92 UlWRb<"o$@lP>{8d;=IlԟB'.JYiU5Qʳx㥤0ܽ9WbẌ́|N 3}}U6WWLF֯0 #м@'֠T%B񁹻Rϕ!QDt#xVù-ݫS/9dys0c _ڴ?Ul궤td(c\ql\>)K6'n']O=RwmL鷓'J>n2:fBeCsFчRqf/0$Q0O,Li_ -ג^Et 9um X|Jyu] o$?%Cډ4/Ay4O di>ԯ˦<}Z:+t2*~eUVH1o cG3bV;0Cph0FP4Mo2x>tq&F'Uu'>ա+σ5ATGzV"k?bicfs]$ʉ3?nDyBM6{7][xqoM C]FNMu-y 8 (ӑ$~Z.E:"yr]p,V?q-хb$7-cpQ}YWj[ذOK5a'Nvtqlc Ψ=VzUp JZ^qˠL1 C봨>2yQ{Wp!݃zo[ 4](cw$D]i`ݡDUy#a.(T[tx"E4 9DZBc QLZ?8!߇]uO^r=}+ythYm^Ʀ,/6QcC8V/lp&eC ;8lNa7-` JJ}'h^ПzQI"(F(¨}.ZN Iz~@U=7nnyeAāI^_;e'GVvⓈ'--(hYDĪ$ǫ2}'jSt=ߐv( *=IAd4*2naD)Ҵce$t - . >11u {l[3 R=OV*;<8ãs97ВQL0bSyn.k b[Q6%vI1)B_Jlpfs8BR8\˽|rt ),8lK`ڍ@Ȁw8jV} PxHflNwy5k4vJ EQ%(?8ìu%r/?f+ku50B @[Y$B[@юDip~ !8fE9`5e?޻ Fnɵw[[Gy +ؾCp\O.i"<,yD[`;[" 'eCD76lYjhƐ֬Z279HSY(YȺޙ:Awp;@SYSE>$+keKy*[mcL |!+2@|zai(ҨNw3_)/b`{ rWJkG[FFNz!t˰Խy :WKaL㺌F+]F'&u'.kߩ('l+_5%LǽI: SYZ kfڛ.Oٹ8S to_>%8ISc\^u:QB$6]@5ߣ4>i9s@Q[6X y50FF<"0eC){ ̯uxK>Fiz(X ~I.[5c}<m^G+"I 1֒!ohoF\X1{X,8D,Uˀmq &S)K/N'F$A1W BszWGPH‰2(u>4QySX#jTuWhnu>0;kQ ^ОMѓ始ZCDB+';ٙC}R/m`8XKi^= CX;C!L-<.MnH3]JJ=*URC 22xQ9~'#g+~KGOݺ=&N0Z5&1m<e.(Ռe'm 2a\R"*`vCmM-`?} x^J2h8Hb_DNMlT >љe;SsLh>en$?,C+j1#+c+eKSY(8jvl,!K=yǿAZ)q=̱-熺  cMƽPc!*_UPs+DY@,!Ʃ:WE78Xr vqk}˳n73OIتf??gh*W&Qkz:?C\MD+ڊvP X~(H*iSm{q<ʟK1yVE(Zzmxb #õDž_?5&#Ճc2}`DqysSӕGūx̴>u8wO]򘺆8&KYY-5v{^H@v=7:WK@M5:Sq,yԌ)$e/>'.b)'j0UYrY z~#F7F~5,>F?`U VJr.=ۨ!dYh7,77 9k;.DuB*D#Zp}n&y-NgEChH( GاM^_@8gW7};,9Ď.+$m6P^}m* w>+,#Si'_〾GzbS6T%]TbwY$^v" :T! 8[Rr4동&i #%Ö3XTsL *pC#te-$8ܼ =46MH$tA.Nȣyno#34FA*'<9\(?FgEh/甆CM7#x:W,]X_D P\_ C"ģ:V^Vؙ޿rkMЩlgd$} d/MACFG^!-犛~ajF@n8,)p#x(pU<Yr4li/0t,wޟsE#Fק,.fsYN&<#nڄ80ξlZ\ןu¶[tPF=l*2D5YLO㋲1`+tN ;ВHaf40|/wΦjdVfN5=exn۞kM<}n6[/i>,Z젾K)cW(ͣ>Ѝ'ꖅ2S{N]drrwSf@*hՖBx~9ϛGbckϘeQ>,B}5aɟa&Mwt3fs`n +f8^;BÜ2sn4˗T=D6q"[Y#뎫&Jҹ ?Y V~bzc 4/5W^d!G c'@S:vyܳv{b;\6f)~.gr ;li4󮦄aF>i\N6|DpFoQ>_ +NUN~ :]XGB2V~fRw 2zVR30Ky@$]b8ytg %PwjsPmLW1,PX"渕I KbLI6£+}ȿfs^;5Xc,df]~( a#`(/= sլ"hH Me\MJLJo4“QE` ծ(~ ilJ󫷰9Kɶa#Īj.S&رG Zi<^H xf_#x6%6?Q<]^R4Nqfٱ)2WX5.K7M$-K"/{zPŪT\oğ?B$ FLC|2'Wѕ/,ska?f~%afbtRǑq:|$L:΋3j]ph`&17{սO v8430?7霨`z "?86U0xf ,B$YTֽ.%[>Tx;dCkV=, }}{ C/|{RK>a\9|,KC#'p{Z_o"ߟx٬~Ax׿%pУU- ;&nr/PG4@.]$+.\xmG"̑=3V ޠ ۢhbAMSA5Gn b'7#*]X0|}dqz2 kiv#>)p#x(pU<Yr4li/0t,wޟsE#Fק,.fsYN&<#nڄ80ξlZ\ןu¶[tPF=l*2D5YLO㋲1`+tN ;ВHaf40|/wΦjdVfN5=exn۞kM<}n6[/i>,Z젾K)cW(ͣ>Ѝ'ꖅ2S{N]drrwSf@*hՖBx~9ϛGbckϘeQ>,B}5aɟa&Mwt3fs`n +f8^;BÜ2sn4˗T=D6q"[Y#뎫&Jҹ ?Y V~bzc 4/5W^d!G c'@S:vyܳv{b;\6f)~.gr ;li4󮦄aF>i\N6|DpFoQ>_ +NUN~ :]XGB2V~fRw 2zVR30Ky@$]b8ytg %PwjsPmLW1,PX"渕I KbLI6£+}ȿfs^;5Xc,df]~( a#`(/= sլ"hH Me\MJLJo4“QE` ծ(~ ilJ󫷰9Kɶa#Īj.S&رG Zi<^H xf_#x6%6?Q<]^R4Nqfٱ)2WX5.K7M$-K"/{zPŪT\oğ?B$ FLC|2'Wѕ/,ska?f~%afbtRǑq:|$L:΋3j]ph`&17{սO v8430?7霨`z "?86U0xf ,B$YTֽ.%[>Tx;dCkV=, }}{ C/|{RK>a\9|,KC#'p{Z_o"ߞߞGSb:ɷ9c"Y>IOHa_xXkT ;$lH-h[}M] 6^:hÚKl<48.3aUcxp B)yS_Q %?1=Fk~zPXf;Pa"ԳIoMGYCGb= 3֜]Ps/K0扏*ʻM>X ֽ )j\y鎿F U+>&yAuMu+]}RM}"h7ǃ+tJjceR!\(7f{Db?|@dvo-$=ӹg(΄&bS :-ŗoԑŏZQ{Ț[1F[ګnFtufMKgW?UלvwD:+n: w) [ls80#_&2aN)>6c]ٱQFpv$b믪OPmpWd1:oSECvO#ʌ X<#FqIL=Wl~*\-AR|Vo F^ё5z[Yz½a3VPc"Ѻi3~ovW3a\2$ v ׹Q mð JF{[DX0˿q#Ul >)¸y Ϥ1PԖ/<׎S.$-[#wK9=GUk.dniS뺊`XUf]RG^qr}r`,𧠊s+윿q&K֐iq "`Ts⭹F9ъwH`չgDJz?ڕB9 `%_q'M#]fdQJQaW{`WA_DhO GROߒ`¤ V=k(wd~Zp]1m}C'MhT={>(rw@l %8|\wھ$Go*ËW oLx5]{;W45ot{ç5oN?F` ,9h F֡h)u* y}৞Si;P[ι&\ kW^ f`9#55 @n,3EO8HTgtOk ;W.b!FUe) A^'b&xʎ:8#?,2t1*LkQhԸt(~d ܓBv,h.4ԩ·VV |@i$+6Pņ؏an3}=jTĔA\kή^lo]sؒs",P+G>-<}Ɲ]Um%{.2ϥB />t;`Y_7+KqJ,0zLhp!ZKGfO#:m#5JTo'}fM P :o?R'.|M@DX6ZiTLGV_M#a5hv#m/=U if/)5OQy|hZk镔>tmm>vayx! ɘ?C rE[:2מ7g]01.tm48d[nQyƤᜄ~󉖠,6٭M veOC:KI8i[ ~Q c +΢>۶J'zs*)g7 mMwFMQIƢo:8Td C)1V&w|e3ݿ쓹0/e/AY` ]L,hښÉPd||a )&Od ,S{/Khu⅊Z#3SnQ( 9F ;rI.NZS 6t$CǁvMg442ۤ,b*!7!c_]D~V?ȃV1N!/6X [snf3liz`!"^u}=/V8$ծyN[yU.x:PB^w+x:P%\mq)& ُ>-ԇoz ܇. ] 9wZ4|zB>3O/F(:XjE_5X @w IFl|'h{[wCPQE'4L&O^fgb3-vEG8jwe]3KoTzb %1ŋ2CrW]MBCxܽ^ 1j|. Nyc+gbIv7m&'qAe5b"];$σqh{IN[ ǫ|uo~ʀdoa٭ R~Lvú=W=ݤ#jz;7PIeaR@}G̘GΗeSc*'2 ϢDz%OȨN=~'Ǯ.Zh ;ƴ.1IdCņEtc62LQӮ FBȃ.qyA#do')[Z[m k[u+Ͻ:v9-GxUC 5&J٤t^eF ZB?n'9 ڿ3M8a- WZQ&%UE fg@yK1jooqf7VB钳9zif':JR 6Mq @BKԋ|!D_yKDDH`NC)!uKzzg@dI!OIcbć\DRU^!h()=+AY6k$GM[7yƒ9op[Z^һvW+,v=!gd{:a4x{▬{!6UtUx27웫JPKhW!溟o=Cp?Y+ٗAC 41ՔD^ X$!dА:|GbF6$/4/0_71t0rpm&q*6Kzd@vmFKy"ٱ%urUpI:caJL\e QІHҰǵ%V^aG L̴Y ;y bR-tfV\$ q@(Fds1"x*mBz:S9bzGR+mn$KIhj1W0NEPONֱ̮'&gi)DIL3O؜%ѱ9t'aHE}WnJPoZD^VXNoGh T,R~ >k@ib5Q 6m*s{GR죚!G5Y5~x>ֆ> 08^ܧ3~lvbciXk X95l jT? "%&S3oj9o$-&kHVmڝ3$ryW7mvo DY"O+@LAzN]w߇,V5zJT[GbuFΝ[/?&X bJ)Ҁ,VYB$#P=qJv2hr>jUm+t? _Xr#PPP˞%MRΙ';"H%~L&[o uB vǺM-T!Od+(w9Ԉ+ЇR+Ft:B$"_״vƘ1,q8SCoa .*ُ/,=jvɥMէ6W9-6>J'!5c|14 P14jQCW#w}̼\ٖLy\#9rgE\Ȫ.Zo-Ao=[p6>rAr_?Mكӛm2 \262@矫fo-ah$6Cv̰]̨q7Uj?ã{k5׫en wQֿ979F{z^#'sdQWÛ{AzܾV3Τܱinҷ+zc6!L2MdtJG7Xal8BrSt:fy881R-`I,7,Wb Q]F+\7 P15c*؝=k1]}18:Nu*cv./8- %1&DZ@=%!\}틥(aG<Κ8x"شM-a&sq$ALQ0R$N$hf`f@[dӇZMĂ.<. cGwlz,E"PBɹ4~.!$2J BXAq'Ʒ:s'&L8J2I^!hIDZv;/˞MjwJ?Gj|yAba_àpʩk3Lдg͗>|a3JBW bE6BCX}/\w. N@_&vH*w/*O6ˍgYde9`:f-H,-bh鼸ǷQΦMex庵Ɩ6ߔ4 c0vmp @Y 3a6:7!v-,-"("4wRqԺ ~plSLilqlCIYv%>uycned _Qzȝ7i[=bo*bL), tհ?tܒEK_9Y2n0ƔAV=i[C_ $&ۂOsRAl7(ZR2f= 9`ORC-kmP\x3G"&H0%%:u%9;5\ˮ|Ba4~*oH O9ϸj:}" A'o<}0M5vA*j?JѬ*LKXh/څ0uz]JVFCeaX`h'2C~eAGeePH )]^N Ude1;Mmus NkC$.ȎY9/\+P+֩yEVE!6wzIa-a.i$~0ςjjcf@P2Լp2ә7Ky2?{%w1R5x@`W7] ZUe?(jq(NL!zp-7(ᬗ 5Cn/[CX &Fc'%)}pN?ۑuPPXZ:ńzb)#jts5voB ytk)-E/n -4W+`3Q)ޙű1gkZ1*k} i ^Li!cx5ܐ q9ZhħÁVbfġ2_)?C/J%5.|7;|2rw|ݴEݾ*rM pa9$h+nG-/KnJFGzpƞ螙됕77MTf诀^J;?֙yY-6N/nPH-ޏ[]:7CfD&we<_}HǾFab{!y7hQccN`o-!|GE $񀝩Rhu(|Du3 )uX! 4cOnO#-e7Pm6pOMћR=}^L/Us?5OQeD8@Vq>J@&5O:Ʉ@Lb1cC36ѷ2au4|tyu`Qwt_ /J,za[0-"HN-|k!$RL-Zu>bnp/V:|яPB^;3-D؀D|I^3(q㋻Lv@XċcU]Cre桌e$[eW`@ ,n]vt@8} s-BE&s9VV47~:!Y,e"8E&|ʦ"!#tQm! ?ij1t@P#xՖCiU::Q4?PDveDGh0DUր}Z66y>g6j+٥꓾ -6+2_C:twhj0kn 3 |nٿ \<\_$i R[27,l@O?ڠCPӋloA鋸āᛀN\¢<G$O\|;Tv"0uYr;k*ϥiwV_?N}#Z~B3=kM^ 'd @mP}%x@uDSS97qA`C,?Ep1y~V-0JY"'wfI_5HviZh}>㭭,iOVa?UscUFz4QTw\LZNi xXd[oXv&"Ȉ\dWR+}+NE Q(Z{z5rIhH=H^~B[7 Jo>UNg|tMN|A'%^u? )1 gSia:Y7cE|t*\BH^lR8&-OӀqM0  E~i3AKUO}Db흓_I9qX')O8B zH/vf&S_X&6}5 PCj'@Z[:?"[ Nס&_`{ e˾G ?fdeEk)pq%R FQ,v \_4;"qd,3hZi!o&bIF8ʿ ex܊E͖Glbt雎v23pԺ:=\hes*.cGn?|%EFhEJI$(5tC:ܝ`^!,~9͸W' c$e8!yV1QGPQ{Dxr (_qnJ/_t#(,@'0FBlTUDrȰX[RMN]dWewcIlw7Z!gЙ=X67I_+VDkw5/}||?QVj;n@m_uO* O r8n5NGIItysuv\fsE3m0dC\'JW_aLjڔ F6dͨAk9D({]z_6jzy3T`(cN^dJ<"B ($cӄfq z/l&rԜՏfuǢ&x?Zcs C3>+11`y};|E7)@p5OM,-JW^c9TGStS/= Np&g% ڨS^@Jj@W)H86jè+'%b_f%a8%(SK;8/={<sl9L#&LH !|e ]G P Ž3/gSw|5_sy `B< ws5)9bnEfH <=HZMĂ֖dQ؇DpiNgb{1fD>SoC6`/mƘz/} `ȩfP1cx7BJ3! dZYS-0MLJ~񑧸WuzS3N@918:i1pHL$hi)QVnBg5JeGȔ:`!y[<9\򘓃YӏGOU˃V nuoI!G˦"3ԥ+.S[ UJQiz)9Cs^nv_wUjѕBhPV3>Ha[Gp7 JKQx~xda*+W~3jkgy>/Os5fͬZĀL{0ύyÈt&+o$(gG~/h免)csA5V" k7O?j;o=(9) yPs ƣ]#v@7W{#'+usp_VיbVajM[ £k-t/m ⒬VnTgC4% `a*h~'mdTc-Z 5fH w$ ;5$0=m`l,[- Y,G [Ճr.YbN5073X& u#!׃BɫrTb_mfQH{$5_Lƛ0&wV./Qvk]%)lE: =@~ɔ  ̿iFyԗ3XnH4UgP" }G} cT$ZsH$ЮYLHN#CҢTw0uPKIvJ2ǂ3}h-zrmAƯ|,ظ~<=Gm2}#ccK;mp?B+>)mV7%8\\NACĞE.{K\ͳ{V$M-lM]Oi`^{WaXeߙ[=.s.!Ⴂ `kdD-fDAv?݈GÂY <.P&'"Ѝ瓍3C =3<p0e;L` qd}U}( (n7&t˝U@m=J@&5O:Ʉ@Lb1cC36ѷ2au4|tyu`Qwt_ /J,za[0-"HN-|k!$RL-Zu>bnp/V:|яPB^;3-D؀D|I^3(q㋻Lv@XċcU]Cre桌e$[eW`@ ,n]vt@8} s-BE&s9VV47~:!Y,e"8E&|ʦ"!#tQm! ?ij1t@P#xՖCiU::Q4?PDveDGh0DUր}Z66y>g6j+٥꓾ -6+2_C:twhj0kn 3 |nٿ \<\_$i R[27,l@O?ڠCPӋloA鋸āᛀN\¢<G$O\|;Tv"0uYr;k*ϥiwV_?N}#Z~B3=kM^ 'd @mP}%x@uDSS97qA`C,?Ep1y~V-0JY"'wfI_5HviZh}>㭭,iOVa?UscUFz4QTw\LZNi xXd[oXv&"Ȉ\dWR+}+NE Q(Z{z5rIhH=H^~B[7 Jo>UNg|tMN|A'%^u? )1 gSia:Y7cE|t*\BH^lR8&-OӀqM0  E~i3AKUO}Db흓_I9qX')O8B zH/vf&S_X&6}5 PCj'@Z[:?"[ Nס&_`{ e˾G ?fdeEk)pq%R FQ,v \_4;"qd,3hZi!o&bIF8ʿ ex܊E͖Glbt雎v23pԺ:=\hes*.cGn?|%EFhEJI$(5tC:ܝ`^!,~9͸W' c$e8!yV1QGPQ{Dxr (_qnJ/_t#(,@'0FBlTUDrȰX[RMN]dWewcIlw7Z!gЙ=X67I_+VDkw5/}||?QVj;n@m_uO* O r8n5NGIItysuv\fsE3m0dC\'JW_aLjڔ F6dͨAk9D({]z_6jzy3T`(cN^dJ<"B ($cӄfq z/l&rԜՏfuǢ&x?Zcs C3>+11`y};|E7)@p5OM,-JW^c9TGStS/= Np&g% ڨS^@Jj@W)H86jè+'%b_f%a8%(SK;8/={<sl9L#&LH !|e ]G P Ž3/gSw|5_sy `B< ws5)9bnEfH <=HZMĂ֖dQ؇DpiNgb{1fD>SoC6`/mƘz/} `ȩfP1cx7BJ3! dZYS-0MLJ~񑧸WuzS3N@918:i1pHL$hi)QVnBg5JeGȔ:`!y[<9\򘓃YӏGOU˃V nuoI!G˦"3ԥ+.S[ UJQiz)9Cs^nv_wUjѕBhPV3>Ha[Gp7 JKQx~xda*+W~3jkgy>/Os5fͬZĀL{0ύyÈt&+o$(gG~/h免)csA5V" k7O?j;o=(9) yPs ƣ]#v@7W{#'+usp_VיbVajM[ £k-t/m ⒬VnTgC4% `a*h~'mdTc-Z 5fH w$ ;5$0=m`l,[- Y,G [Ճr.YbN5073X& u#!׃BɫrTb_mfQH{$5_Lƛ0&wV./Qvk]%)lE: =@~ɔ  ̿iFyԗ3XnH4UgP" }G} cT$ZsH$ЮYLHN#CҢTw0uPKIvJ2ǂ3}h-zrmAƯ|,ظ~<=Gm2}#ccK;mp?B+>)mV7%8\\NACĞE.{K\ͳ{V$M-lM]Oi`^{WaXeߙ[=.s.!Ⴂ `kdD-fDAv?݈GÂY <.P&'"Ѝ瓍3C =3<p0e;L` qd}U}( (n7&t˝U@m=o?muYגre7T&y=%_x I40C ^Щ?$(8dsZZ䬇V;n5y(!~ ²(JRyV\Ǚ5=Ah}9& ia V^Aj$-`!bRdpٜ,(@z,}9cJXQ!¹45k{XBpJjI puM/`gn< 으y0[ch6#nSK5CISU9>=V{\FTA@fqpm`%FS=ȳ] ~7@5?nHw5ٍ2`O*>[@>jb5l2_}fE- I4FPFhya$(;RJ6ϝ}ÏsB϶_lO,jf`#2eB. *XWq@e_R/7- T>!{6gR("/ r0kH[q\ 1 EgPX1+޲Y]\un()V`藍?rqNAk?q#"<~6zv;j9 +6\SwxH|vϢLk`V2k<.$ CSl'Iuw7p0 >F|81A_v" LYN!SkQ7Kg4(,L*Պ'z,oNb9O^s\f5']"KG)"lO ${rBSG m,&67,F޷i/4BЩyN݇'Zb5$qlyA*yG8Pߟp݂;Y&\nevElb / ts:~'|xo#ql,? ?ĹNhL,mͽo,c6QkLp4屐l]9,˘Cgý{zYrN׭\V**uK=?gg28i1FIҿL]@߷}okA{wP4όQsA}2\P7s $R%ռCvL)8yq7^@7 WBo$¨NB;>ԗ0K\EMf35`_KG[3 }_- Q"2(qcSCr'5bL{\l3 ~oQ:A}5i-&@K>/iw%@ ."TO(CHS̠3ۖzox=Vy۲&$2*i0JCD>nF,p2HKS t4طOl"˜rA|JPSl4kS,MuOyxKEq8ZV#FGU ꌖ{D87bl&ͦت['josx4t3ߦ!Mt|^4o5L#T]}1PFO(8qP쥀# TG0ƪN滗{<2Bmldemos-0.4.3/MLDemos/logo.png000066400000000000000000000371711172143270300161350ustar00rootroot00000000000000PNG  IHDR\rf pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F3IDATx{xUizoz%mƩQ92 9q胃?<*XxE:fJBS "kJڤGԷ!I>ϳ&-&kKA"q9RD]]-6'l^+@yE׌`kA/x3a\Ղ?O "ro; K &bXFC91tX$b?`BG|:;сКnk v6txyᤏ8g0 *fB/B- =~LHm!! hĘ~Ә), WbbPoj'WN {!Hep7z31M&x*xGر8wL_"v%F <3{2P0FF|L a6㣊 olMY6w0l_!z|BM q|OB#%`T nl,-PeRh殮QMb"VH殮uz!?7yDop:v, A}w WZZ =M|\b!0dOT=B:R~;uJTу=yd,&>0?}TJtdaVA$HzUSXKF^7aOyy!BXbXĮ|܌0r JHQ`5x 0', -:t:ZP`` T*3gmܸN8AtV%S~>0t:6J':ъ$GAɓF\t-[F2ޭ=*[-DQ29IHIVZ֬YCǎVor{H,,,w2Q:]0֧JH뮻hʕtajiiN&֮]KnX+ _%rT:4v,}c@YYY|r:p555 m1 G`%z؛0rlW9pz{A¥,g {/$4a̤²ޔ)ShtI2䊼W_f` atdZRpp0%%%ѓO>I{Fru:d/H -5Xvs2s!&̤ǓJロ֯_Od2ȝXn =0{bRImlNl婩ʄ V)==x ڿ?555w^JJJr\8Jubgf&7̤Gbc),,fΜI.]x0xbۡW'=a4e.(.'%Ѻ z'ߛv܉>0\0%.KbțwZ NG i…g;:5kP5(u(:x* (44RSS_ӧOS{{;y?#Q,Co:K*~ڲe Ԑ'cgܕ Ћ*$0m7*>JͥnD͛m/ֳ8h?s^Hk\W^yˇ|ˮgf`yrXvmK کtZѐR3f{GW^ek|L4`pƟ+~iZx8GDa:#ϏIT((**}Qڳg"##ms. |-Ty3ZGX}IJ==zewfdLryt&%a:q}cZjȠ+VPYYw'L&M/յ&9|||o 6˗o; C,_OIatR2~J^]1"2]{NiJ%RPP͛7 9bL8ѶpˉAgK bGGð0mmԩSpBdddϏ;Džx7k l)EF_aoH mn;?k,>w Xp!Ýb㣏>`s6mHT'NnaK^߭O;0{1*_) JW6-}|-nbhRIZ^uF<䓶[ )4_W6:ͥ"2LTTTD]չA  O?MlUnh=p`Kn' {=+Dop꽑&9iܹTRR‰>nȾ}li[ 0Z M)//'XΦ/x1k֬9 +E֗j4n1o>oOFc4 ޅj5iZZ~=5779YYYb*rTy JdBY]]m} ƨ(l7MӧC&^r<He&&»-:{sݺuv߷>??cbBE1w\DGG233;_ZG;)8Se P\\LDDV\sWO@PBB_ # ^o*z1 Qw<>& ژF!!!ZF  \J:wye_/Cnvz<#j5y睴w^2l-*P'؜WX? n; BO ׮R3FFsD3g"==^^^0\JT ն%!BHNNԩSʝ2_.}%듏%&BVYw ~_SLARR$N 3fĉRO$%3O蠟t4\VEvv6S<7|S|97YAf=VB=N#"\T;ZDzz:VXq :]$2Z\w \T( ɸ; `[tH,֧D+ %R)ZZZp#-- c̆ɐx('V#fZ ::Vlf/ 'GVh"4 $qҏi޼ytܹb0lwu'r3]V/8"h,zbܨQsw||pBi#~ϋ/B_d/ 'ryױ1j%ֹF-I4U//DEE!99yė޼yM HRX!a?">v-I\ Amm-4 ƍ7~{= f x4~<3 B*E{{;ƍ'>DbĢûTcɒl Q^w8o2! #;/XX./@̬םa BXX=bҥKml,]@xx8rss/-rH9,(L;{{݉r #@*b˃^T*^G^^v Tg/`,60Fqg / r9F1[*bѢE(**dBQQ-ZoV,/Y5c}; v#,,;˲eė 0B%;=dZ`2@fp̜9QQQK ,{JŽ<: s .?z^:<(ڗ0@<;L=OT*z2@A l!JeEn ߕ!?s{v$ĝl>@`<Ue`~:`׶zyVwܧJljjB[[w'6$)w0燆444p0}2gNDx:vt 00uuuz*w'Rv0s 0!44.]•+Wx54 yuuX`4,L9O/`"8ǵܹf$ 0 )L&eGdc682ĚLCYY.L?6mZ*AaLK "##QVV'O44wNtB@EE;_qݪK$<\шt//H$pYlfӀ;%o.G\CfFgg'w //؊ 9W?0TVV)l+$e 7#22= `$55ۥD" d]r x95;iY+c`Lƽx]ɝ@AAJJJx0'"fv`wibϟdzx"[0}"]F_=.]k+섿?كtttp0!((1\ٳx)(رcʸSh4.@0^`V\ 11c޽Oq5ƾ("##R.v xv C{{;K8pL.-נw+2Rt4.\?NNa2~n`=gk=Fx748wEBB"##1f8m Ja-m۶O?ESSw ӧ`ȟ{ PZCCQ]]͛7c޽~:w ӻ HB{"1qWe%j?6mL7d26L"zCT/>C#'H&/CB?, U&Q0b+-cٌm۶a8wyغu+$ ~_!!!{ wX XRo=@b^.$~!֬YgrL \ Jrxi*V:p ?Ex|Iqqh'Nш`Ou! H M0W\d2Թy2!!۷W_Ł Mcڵbbbp0+HVqCTߟ-dc4ku]J+k|8y刳S󈏏GrgΝCJJ ,XgG,/_Ftttץ@Pw?킺p:_\G *zb֬Y;w.4illDXXXץR`Byy|X]477?k#GG$Ri7szp ֭y|o͸15, SM&l۶ yyyؿ?G }deŌ*;\*..&"bzʍ3ڹ4ZѐB3fG}DW^%Od2ʕ+)##PFF\L&[~eD~/uCޯV;nBIoz ʲ;&NH@ %nڤx (.r"; : =.P_4ooGEasEΜ9 B[!X|9lb*)S;Y0pUM\~Dx999HHH~{|?..҂K/XV |2jn7}vlܸj$kf`zDb4Ç(2>>>裏n:9sc6)zhk5 Yݑ#صkz-M`zհhV2G¹NӯJzΞ=K#~ 0;;*@vv-=zTzhJczd‘#x""6mr9@Jؽ{7!J둗ݻwfֹ<.%=vtWu:xc1nΝ;1k֬K/ɷq1 l5 >vG ݪbwf;;:;qx5, Νƍg3&Poe97nmOnXTUU>@ii)tqjkk]v|[[(((m?pǸp{AUUxH*>>صk>qǸ(/_v|0(3ǎ1cP__m۶aKbs0LE78|*3(n/+XTTT`۶m8s w;5BH=fx75*(=[#q"P 5Z]?ndv d_Wpeee.*K:pÏ%fWUaLÇc׮]N0rnb蒆A[[{R/ľ}l3t$cǰ:<oq%JohbnNa0 ** ¿/\nvRa˗w*/1+fY5wM $n2}.6l?JU{i.`i` .\B-8:tnWL=4^-- ^^^(..Fee%w;@>g2BЀ(>}ǏDAAAP(q3BVY?͸t?Ӏal6lWRzm q4`)YZZ?"j@` ^Phi\.QVVƫNf7xOq1" pep2kK*tƻ ~~vXTRRɽ8f@T ۺtDt7cc0hDHHl1C_|qmK`{cftt@&׮]@B'DŽ1u-hm(d92x61{i|F`0W>^~dw[֭[׫ߗpZ00$f3AD\ I嬀0 DD@'uVeD< `I$D"7ws=r/N0Sv[@ !sR__FK )۷o_Ŗv407ALD2D^l'1F#kM ?[-ԋt:afP5j 6/wbÃ`u\E03(=z4wo`7%dI!,uuhHH^fLDZQFq _|xeD)7V/X հ!phDXXJ%y /€`$7GW׷z`PT08qv ֱ[ `V=nzsEQQL& {Z=Z uuuPT;v, o>jDdiCȰ^*"n7B=rss yR|Q`` =3Lc5׌>]h^!˙_[KyI>עEo}}h OJJB`` }CtbVX==oCSP}zɕl2VCMY9V ..yUO` xywMaV/`{}g]?g66 RF*6B拉QLL =ct)2^k\\KC[:B,XZѰNGQQQ4i$]pui*_ *¼*08?_ LYfnK}ƞ*3Te@[(eBת1cjF p:>okÌ3p}d ?ۨpؙ t 7,- o_ ???̝;wyC(bbbcđ#G_*_;Er0,˻jjvP5f3kmԩSCARq8TUUY/[qaC`J32xn­EWZ _TPP@ׯ_ɺy&bldYA@;"L0EMr2;>ڽ{Gݍ 6ؚ2=K%f΅Z[t4JtwW_}6;܅/,v9fpJ"둑l|. 111-T*M4oN---ld$H&qP l?PDd)$#BH[L >j7O>$n)18|0f͚eyZlmX>px"O @j5Iv?s=}p \V{lCԪZZ@t7|Gx/lyp!]ZX"7px;FK(::͛G{e~ӟ%ý  rpLAˋXR(cQaas~4X/K"$!oLRTG{`[oK"eZ =ƌCIII?.^貥ܕCQZZKZD&KBC9mx&1VjP(;?OTUUEl"""l\ B*7KKgƍiǎ:{lr˜ D [6[{nf{f&-P(>>z!H`gKo0V04{.ENFo3$#T*?z):|0v^tvnG QJ6t9)^0)##V^M.\pJ]]͚5vh&XSO`X~Imcxf~*艸8RtLW^eku0X!YYz(/=wC;u:R4vXOڿ?v; ,4Z'z DUZ-4aPJJ Ktis0F=3f8D #ɕZ!!/3~VJ3g҇~H555l'%%%bál婩#%$TR*Hov֭76|ߣ@$mj4nBl $!hĉf*//Vfeeal5#^DJ6@O32}=}t5VyfR{SzY#ϊS-NHQfy4#j4Cz+ t1Nq0$^o;1x"!Zcj5E#RI4gڹs']rw95k:G' J%5rsҌ ZHєN>,S|jmA+R@Ɔ#5Bpt6uL;n^z9Bmmml_b!Qa0<" 6H N\)Rer2KIHR4|ꫯ{H& c,o70)4*L0aT*:u*tY^w oۻF0=7L5Z~QTTZx1޽w!\nVc? s3 2DLJ*鍔C> m޼*++jjjhj |,G%@d׍GhܸqP(hҤI/Sii))77[yJ  I!d+%&GЬV33xR*t-ТE(??r?qĞnQIY!lsB0#"D\Nu:zZ!\N4|ںu+UUUqŋl2V ["Kz"X>w=]ϟ1Dýދɓ'CRϏ;qcXf fp.*B_BKٞZj577{L&ڶm͞=7p<>ov pNR:{lzww>0ǧ#/U޽<"4&IENDB`mldemos-0.4.3/MLDemos/main.cpp000066400000000000000000000024151172143270300161100ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include #include //Q_IMPORT_PLUGIN(mld_classifySVM) int main(int argc, char *argv[]) { QApplication a(argc, argv); QString filename = ""; if(argc > 1) filename = QString(argv[1]); MLDemos w(filename); w.show(); return a.exec(); } mldemos-0.4.3/MLDemos/manualSelection.ui000066400000000000000000000105101172143270300201350ustar00rootroot00000000000000 ManualSelection 0 0 355 320 Manual Selection of Training Samples QAbstractItemView::MultiSelection Test: 0 Train: 0 0 0 10 Randomly select samples Randomize true true 0 0 70 16777215 9 4 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 10 Invert 10 Clear 10 Remove selected samples from the canvas Remove Selected mldemos-0.4.3/MLDemos/mldemos.cpp000066400000000000000000002762421172143270300166370ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include #include #include #include #include #include #include #include #include "basicMath.h" #include "drawSVG.h" #include #include #include "optimization_test_functions.h" MLDemos::MLDemos(QString filename, QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags), canvas(0), expose(0), classifier(0), regressor(0), dynamical(0), clusterer(0), maximizer(0), projector(0), bIsRocNew(true), bIsCrossNew(true), compareDisplay(0), compare(0), trajectory(ipair(-1,-1)), bNewObstacle(false), tabUsedForTraining(0) { QApplication::setWindowIcon(QIcon(":/MLDemos/logo.png")); ui.setupUi(this); setAcceptDrops(true); connect(ui.actionExit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(ShowAbout())); connect(ui.actionClearData, SIGNAL(triggered()), this, SLOT(ClearData())); connect(ui.actionClearModel, SIGNAL(triggered()), this, SLOT(Clear())); connect(ui.actionNew, SIGNAL(triggered()), this, SLOT(ClearData())); connect(ui.actionSave, SIGNAL(triggered()), this, SLOT(SaveData())); connect(ui.actionLoad, SIGNAL(triggered()), this, SLOT(LoadData())); connect(ui.actionImportData, SIGNAL(triggered()), this, SLOT(ImportData())); connect(ui.actionExportOutput, SIGNAL(triggered()), this, SLOT(ExportOutput())); connect(ui.actionExportAnimation, SIGNAL(triggered()), this, SLOT(ExportAnimation())); connect(ui.actionExport_SVG, SIGNAL(triggered()), this, SLOT(ExportSVG())); initDialogs(); initToolBars(); initPlugins(); LoadLayoutOptions(); SetTextFontSize(); ShowToolbar(); this->show(); DisplayOptionChanged(); UpdateInfo(); FitToData(); AlgoChanged(); if(!classifiers.size()) algorithmOptions->tabWidget->setTabEnabled(0,false); if(!clusterers.size()) algorithmOptions->tabWidget->setTabEnabled(1,false); if(!regressors.size()) algorithmOptions->tabWidget->setTabEnabled(2,false); if(!projectors.size()) algorithmOptions->tabWidget->setTabEnabled(3,false); if(!dynamicals.size()) algorithmOptions->tabWidget->setTabEnabled(4,false); if(!maximizers.size()) algorithmOptions->tabWidget->setTabEnabled(5,false); algorithmWidget->setFixedSize(636,220); canvas->repaint(); canvas->ResizeEvent(); CanvasMoveEvent(); CanvasTypeChanged(); CanvasOptionsChanged(); drawTime.start(); if(filename != "") Load(filename); } void MLDemos::initToolBars() { actionNew = new QAction(QIcon(":/MLDemos/icons/new.png"), tr("&New"), this); actionNew->setShortcut(QKeySequence(tr("Ctrl+N"))); actionNew->setStatusTip(tr("Clear Everything")); actionSave = new QAction(QIcon(":/MLDemos/icons/save.png"), tr("&Save"), this); actionSave->setShortcut(QKeySequence(tr("Ctrl+S"))); actionSave->setStatusTip(tr("Save Data")); actionLoad = new QAction(QIcon(":/MLDemos/icons/load.png"), tr("&Load"), this); actionLoad->setShortcut(QKeySequence(tr("Ctrl+L"))); actionLoad->setStatusTip(tr("Load Data")); actionAlgorithms = new QAction(QIcon(":/MLDemos/icons/algorithms.png"), tr("&Algorithms"), this); actionAlgorithms->setShortcut(QKeySequence(tr("C"))); actionAlgorithms->setStatusTip(tr("Algorithm Options")); actionAlgorithms->setCheckable(true); actionCompare = new QAction(QIcon(":/MLDemos/icons/compare.png"), tr("&Compare"), this); actionCompare->setShortcut(QKeySequence(tr("M"))); actionCompare->setStatusTip(tr("Compare Algorithms")); actionCompare->setCheckable(true); actionDrawSamples = new QAction(QIcon(":/MLDemos/icons/draw.png"), tr("&Drawing"), this); actionDrawSamples->setShortcut(QKeySequence(tr("W"))); actionDrawSamples->setStatusTip(tr("Show Sample Drawing Options")); actionDrawSamples->setCheckable(true); actionClearModel = new QAction(QIcon(":/MLDemos/icons/clearmodel.png"), tr("Clear Model"), this); actionClearModel->setShortcut(QKeySequence(tr("Shift+X"))); actionClearModel->setStatusTip(tr("Clear current model")); actionClearData = new QAction(QIcon(":/MLDemos/icons/cleardata.png"), tr("Clear Data"), this); actionClearData->setShortcut(QKeySequence(tr("X"))); actionClearData->setStatusTip(tr("Clear all data")); actionScreenshot = new QAction(QIcon(":/MLDemos/icons/screenshot.png"), tr("Save Screenshot"), this); actionScreenshot->setShortcut(QKeySequence(tr("Alt+S"))); actionScreenshot->setStatusTip(tr("Save the current image to disk")); actionDisplayOptions = new QAction(QIcon(":/MLDemos/icons/display.png"), tr("Display &Options"), this); actionDisplayOptions->setShortcut(QKeySequence(tr("O"))); actionDisplayOptions->setStatusTip(tr("Show Display Options")); actionDisplayOptions->setCheckable(true); actionShowStats = new QAction(QIcon(":/MLDemos/icons/stats.png"), tr("Info/Statistics"), this); actionShowStats->setShortcut(QKeySequence(tr("I"))); actionShowStats->setStatusTip(tr("Display Algorithm Information and Data Statistics")); actionShowStats->setCheckable(true); connect(actionAlgorithms, SIGNAL(triggered()), this, SLOT(ShowAlgorithmOptions())); connect(actionCompare, SIGNAL(triggered()), this, SLOT(ShowOptionCompare())); connect(actionDrawSamples, SIGNAL(triggered()), this, SLOT(ShowSampleDrawing())); connect(actionDisplayOptions, SIGNAL(triggered()), this, SLOT(ShowOptionDisplay())); connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData())); connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear())); connect(actionScreenshot, SIGNAL(triggered()), this, SLOT(Screenshot())); connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData())); connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData())); connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData())); connect(actionShowStats, SIGNAL(triggered()), this, SLOT(ShowStatsDialog())); /* connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData())); connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear())); connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData())); connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData())); connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData())); */ toolBar = addToolBar("Tools"); toolBar->setObjectName("MainToolBar"); toolBar->setMovable(false); toolBar->setFloatable(false); toolBar->setIconSize(QSize(32,32)); toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); toolBar->addAction(actionNew); toolBar->addAction(actionLoad); toolBar->addAction(actionSave); toolBar->addSeparator(); toolBar->addAction(actionAlgorithms); toolBar->addAction(actionCompare); toolBar->addSeparator(); toolBar->addAction(actionClearModel); toolBar->addAction(actionClearData); toolBar->addSeparator(); toolBar->addAction(actionDrawSamples); toolBar->addSeparator(); toolBar->addAction(actionScreenshot); toolBar->addAction(actionDisplayOptions); toolBar->addAction(actionShowStats); toolBar->setVisible(true); connect(toolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(ShowToolbar())); connect(ui.actionShow_Toolbar, SIGNAL(triggered()), this, SLOT(ShowToolbar())); connect(ui.actionSmall_Icons, SIGNAL(triggered()), this, SLOT(ShowToolbar())); connect(ui.canvasTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(CanvasTypeChanged())); connect(ui.canvasZoomSlider, SIGNAL(valueChanged(int)), this, SLOT(CanvasOptionsChanged())); connect(ui.canvasX1Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged())); connect(ui.canvasX2Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged())); connect(ui.canvasX3Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged())); QSize iconSize(24,24); drawToolbar->singleButton->setIcon(QIcon(":/MLDemos/icons/brush.png")); drawToolbar->singleButton->setIconSize(iconSize); drawToolbar->singleButton->setText(""); drawToolbar->sprayButton->setIcon(QIcon(":/MLDemos/icons/airbrush.png")); drawToolbar->sprayButton->setIconSize(iconSize); drawToolbar->sprayButton->setText(""); drawToolbar->eraseButton->setIcon(QIcon(":/MLDemos/icons/erase.png")); drawToolbar->eraseButton->setIconSize(iconSize); drawToolbar->eraseButton->setText(""); drawToolbar->trajectoryButton->setIcon(QIcon(":/MLDemos/icons/trajectory.png")); drawToolbar->trajectoryButton->setIconSize(iconSize); drawToolbar->trajectoryButton->setText(""); drawToolbar->lineButton->setIcon(QIcon(":/MLDemos/icons/line.png")); drawToolbar->lineButton->setIconSize(iconSize); drawToolbar->lineButton->setText(""); drawToolbar->ellipseButton->setIcon(QIcon(":/MLDemos/icons/ellipse.png")); drawToolbar->ellipseButton->setIconSize(iconSize); drawToolbar->ellipseButton->setText(""); drawToolbar->paintButton->setIcon(QIcon(":/MLDemos/icons/bigbrush.png")); drawToolbar->paintButton->setIconSize(iconSize); drawToolbar->paintButton->setText(""); drawToolbar->obstacleButton->setIcon(QIcon(":/MLDemos/icons/obstacle.png")); drawToolbar->obstacleButton->setIconSize(iconSize); drawToolbar->obstacleButton->setText(""); } void MLDemos::initDialogs() { drawToolbar = new Ui::DrawingToolbar(); drawToolbarContext1 = new Ui::DrawingToolbarContext1(); drawToolbarContext2 = new Ui::DrawingToolbarContext2(); drawToolbarContext3 = new Ui::DrawingToolbarContext3(); drawToolbarContext4 = new Ui::DrawingToolbarContext4(); drawToolbar->setupUi(drawToolbarWidget = new QWidget()); drawToolbarContext1->setupUi(drawContext1Widget = new QWidget()); drawToolbarContext2->setupUi(drawContext2Widget = new QWidget()); drawToolbarContext3->setupUi(drawContext3Widget = new QWidget()); drawToolbarContext4->setupUi(drawContext4Widget = new QWidget()); connect(qApp, SIGNAL(focusChanged(QWidget *,QWidget *)),this,SLOT(FocusChanged(QWidget *,QWidget *))); drawToolbar->sprayButton->setContextMenuPolicy(Qt::CustomContextMenu); drawToolbar->ellipseButton->setContextMenuPolicy(Qt::CustomContextMenu); drawToolbar->lineButton->setContextMenuPolicy(Qt::CustomContextMenu); drawToolbar->eraseButton->setContextMenuPolicy(Qt::CustomContextMenu); drawToolbar->obstacleButton->setContextMenuPolicy(Qt::CustomContextMenu); drawToolbar->paintButton->setContextMenuPolicy(Qt::CustomContextMenu); connect(drawToolbar->sprayButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuSpray(const QPoint &))); connect(drawToolbar->ellipseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuEllipse(const QPoint &))); connect(drawToolbar->lineButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuLine(const QPoint &))); connect(drawToolbar->eraseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuErase(const QPoint &))); connect(drawToolbar->obstacleButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuObstacle(const QPoint &))); connect(drawToolbar->paintButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuReward(const QPoint &))); displayOptions = new Ui::viewOptionDialog(); aboutPanel = new Ui::aboutDialog(); showStats = new Ui::statisticsDialog(); manualSelection = new Ui::ManualSelection(); inputDimensions = new Ui::InputDimensions(); displayOptions->setupUi(displayDialog = new QDialog()); aboutPanel->setupUi(about = new QDialog()); showStats->setupUi(statsDialog = new QDialog()); manualSelection->setupUi(manualSelectDialog = new QDialog()); inputDimensions->setupUi(inputDimensionsDialog = new QDialog()); rocWidget = new QNamedWindow("ROC Curve", false, showStats->rocWidget); infoWidget = new QNamedWindow("Info", false, showStats->informationWidget); connect(showStats->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(StatsChanged())); connect(rocWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged())); connect(infoWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged())); connect(manualSelection->sampleList, SIGNAL(itemSelectionChanged()), this, SLOT(ManualSelectionChanged())); connect(manualSelection->clearSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionClear())); connect(manualSelection->invertSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionInvert())); connect(manualSelection->removeSampleButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRemove())); connect(manualSelection->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRandom())); connect(inputDimensions->dimList, SIGNAL(itemSelectionChanged()), this, SLOT(InputDimensionsChanged())); connect(inputDimensions->clearSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsClear())); connect(inputDimensions->invertSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsInvert())); connect(inputDimensions->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsRandom())); connect(drawToolbar->singleButton, SIGNAL(clicked()), this, SLOT(DrawSingle())); connect(drawToolbar->sprayButton, SIGNAL(clicked()), this, SLOT(DrawSpray())); connect(drawToolbar->lineButton, SIGNAL(clicked()), this, SLOT(DrawLine())); connect(drawToolbar->ellipseButton, SIGNAL(clicked()), this, SLOT(DrawEllipse())); connect(drawToolbar->eraseButton, SIGNAL(clicked()), this, SLOT(DrawErase())); connect(drawToolbar->trajectoryButton, SIGNAL(clicked()), this, SLOT(DrawTrajectory())); connect(drawToolbar->obstacleButton, SIGNAL(clicked()), this, SLOT(DrawObstacle())); connect(drawToolbar->paintButton, SIGNAL(clicked()), this, SLOT(DrawPaint())); connect(displayOptions->clipboardButton, SIGNAL(clicked()), this, SLOT(ToClipboard())); connect(displayOptions->mapCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged())); connect(displayOptions->modelCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged())); connect(displayOptions->infoCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged())); connect(displayOptions->samplesCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged())); connect(displayOptions->gridCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged())); connect(displayOptions->spinZoom, SIGNAL(valueChanged(double)), this, SLOT(DisplayOptionChanged())); connect(displayOptions->zoomFitButton, SIGNAL(clicked()), this, SLOT(FitToData())); algorithmOptions = new Ui::algorithmOptions(); optionsClassify = new Ui::optionsClassifyWidget(); optionsCluster = new Ui::optionsClusterWidget(); optionsRegress = new Ui::optionsRegressWidget(); optionsDynamic = new Ui::optionsDynamicWidget(); optionsMaximize = new Ui::optionsMaximizeWidget(); optionsProject = new Ui::optionsProjectWidget(); optionsCompare = new Ui::optionsCompare(); algorithmWidget = new QWidget(); algorithmOptions->setupUi(algorithmWidget); algorithmWidget->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac //algorithmWidget->setWindowFlags(Qt::WindowStaysOnTopHint); displayDialog->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac //drawToolbarWidget->setWindowFlags(Qt::Tool); drawToolbarWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Tool | Qt::WindowTitleHint); drawContext1Widget->setWindowFlags(Qt::FramelessWindowHint); drawContext2Widget->setWindowFlags(Qt::FramelessWindowHint); drawContext3Widget->setWindowFlags(Qt::FramelessWindowHint); drawContext4Widget->setWindowFlags(Qt::FramelessWindowHint); drawToolbarWidget->setFixedSize(drawToolbarWidget->size()); classifyWidget = new QWidget(algorithmOptions->tabClass); clusterWidget = new QWidget(algorithmOptions->tabClust); regressWidget = new QWidget(algorithmOptions->tabRegr); dynamicWidget = new QWidget(algorithmOptions->tabDyn); maximizeWidget = new QWidget(algorithmOptions->tabMax); projectWidget = new QWidget(algorithmOptions->tabProj); optionsClassify->setupUi(classifyWidget); optionsCluster->setupUi(clusterWidget); optionsRegress->setupUi(regressWidget); optionsDynamic->setupUi(dynamicWidget); optionsMaximize->setupUi(maximizeWidget); optionsProject->setupUi(projectWidget); compareWidget = new QWidget(); optionsCompare->setupUi(compareWidget); connect(displayDialog, SIGNAL(rejected()), this, SLOT(HideOptionDisplay())); connect(statsDialog, SIGNAL(rejected()), this, SLOT(HideStatsDialog())); //connect(manualSelectDialog, SIGNAL(rejected()), this, SLOT(HideManualSelectionDialog())); connect(optionsClassify->classifyButton, SIGNAL(clicked()), this, SLOT(Classify())); connect(optionsClassify->clearButton, SIGNAL(clicked()), this, SLOT(Clear())); connect(optionsClassify->rocButton, SIGNAL(clicked()), this, SLOT(ShowRoc())); connect(optionsClassify->crossValidButton, SIGNAL(clicked()), this, SLOT(ClassifyCross())); connect(optionsClassify->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd())); connect(optionsClassify->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection())); connect(optionsClassify->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions())); connect(optionsRegress->regressionButton, SIGNAL(clicked()), this, SLOT(Regression())); connect(optionsRegress->crossValidButton, SIGNAL(clicked()), this, SLOT(RegressionCross())); connect(optionsRegress->clearButton, SIGNAL(clicked()), this, SLOT(Clear())); //connect(optionsRegress->svmTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions())); connect(optionsRegress->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd())); connect(optionsRegress->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection())); connect(optionsRegress->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions())); connect(optionsCluster->clusterButton, SIGNAL(clicked()), this, SLOT(Cluster())); connect(optionsCluster->iterationButton, SIGNAL(clicked()), this, SLOT(ClusterIterate())); connect(optionsCluster->optimizeButton, SIGNAL(clicked()), this, SLOT(ClusterOptimize())); connect(optionsCluster->clearButton, SIGNAL(clicked()), this, SLOT(Clear())); connect(optionsCluster->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection())); connect(optionsDynamic->regressionButton, SIGNAL(clicked()), this, SLOT(Dynamize())); connect(optionsDynamic->clearButton, SIGNAL(clicked()), this, SLOT(Clear())); connect(optionsDynamic->centerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions())); connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions())); connect(optionsDynamic->resampleSpin, SIGNAL(valueChanged(int)), this, SLOT(ChangeActiveOptions())); connect(optionsDynamic->dtSpin, SIGNAL(valueChanged(double)), this, SLOT(ChangeActiveOptions())); connect(optionsDynamic->obstacleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(AvoidOptionChanged())); connect(optionsDynamic->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd())); connect(optionsDynamic->colorCheck, SIGNAL(clicked()), this, SLOT(ColorMapChanged())); connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions())); connect(optionsMaximize->maximizeButton, SIGNAL(clicked()), this, SLOT(Maximize())); connect(optionsMaximize->pauseButton, SIGNAL(clicked()), this, SLOT(MaximizeContinue())); connect(optionsMaximize->clearButton, SIGNAL(clicked()), this, SLOT(Clear())); connect(optionsMaximize->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton())); connect(optionsMaximize->gaussianButton, SIGNAL(pressed()), this, SLOT(GaussianButton())); connect(optionsMaximize->gradientButton, SIGNAL(pressed()), this, SLOT(GradientButton())); connect(optionsMaximize->benchmarkButton, SIGNAL(clicked()), this, SLOT(BenchmarkButton())); connect(optionsMaximize->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd())); connect(optionsProject->projectButton, SIGNAL(clicked()), this, SLOT(Project())); connect(optionsProject->revertButton, SIGNAL(clicked()), this, SLOT(ProjectRevert())); connect(optionsProject->reprojectButton, SIGNAL(clicked()), this, SLOT(ProjectReproject())); connect(optionsProject->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection())); connect(optionsCompare->compareButton, SIGNAL(clicked()), this, SLOT(Compare())); connect(optionsCompare->screenshotButton, SIGNAL(clicked()), this, SLOT(CompareScreenshot())); connect(optionsCompare->clearButton, SIGNAL(clicked()), this, SLOT(CompareClear())); connect(optionsCompare->removeButton, SIGNAL(clicked()), this, SLOT(CompareRemove())); connect(optionsCompare->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions())); connect(optionsRegress->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsCompare->outputDimCombo, SLOT(setCurrentIndex(int))); connect(optionsCompare->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsRegress->outputDimCombo, SLOT(setCurrentIndex(int))); optionsClassify->tabWidget->clear(); optionsCluster->tabWidget->clear(); optionsRegress->tabWidget->clear(); optionsDynamic->tabWidget->clear(); optionsMaximize->tabWidget->clear(); optionsProject->tabWidget->clear(); optionsClassify->tabWidget->setUsesScrollButtons(true); optionsCluster->tabWidget->setUsesScrollButtons(true); optionsRegress->tabWidget->setUsesScrollButtons(true); optionsDynamic->tabWidget->setUsesScrollButtons(true); optionsMaximize->tabWidget->setUsesScrollButtons(true); optionsProject->tabWidget->setUsesScrollButtons(true); QHBoxLayout *layout = new QHBoxLayout(optionsCompare->resultWidget); compare = new CompareAlgorithms(optionsCompare->resultWidget); connect(algorithmOptions->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsClassify->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsCluster->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsRegress->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsDynamic->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsMaximize->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); connect(optionsProject->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged())); //canvas = new Canvas(ui.centralWidget); canvas = new Canvas(ui.canvasWidget); connect(canvas, SIGNAL(Drawing(fvec,int)), this, SLOT(Drawing(fvec,int))); connect(canvas, SIGNAL(DrawCrosshair()), this, SLOT(DrawCrosshair())); connect(canvas, SIGNAL(Navigation(fvec)), this, SLOT(Navigation(fvec))); connect(canvas, SIGNAL(Released()), this, SLOT(DrawingStopped())); connect(canvas, SIGNAL(CanvasMoveEvent()), this, SLOT(CanvasMoveEvent())); //connect(canvas, SIGNAL(ZoomChanged()), this, SLOT(ZoomChanged())); drawTimer = new DrawTimer(canvas, &mutex); drawTimer->classifier = &classifier; drawTimer->regressor = ®ressor; drawTimer->dynamical = &dynamical; drawTimer->clusterer = &clusterer; drawTimer->maximizer = &maximizer; connect(drawTimer, SIGNAL(MapReady(QImage)), canvas, SLOT(SetConfidenceMap(QImage))); connect(drawTimer, SIGNAL(ModelReady(QImage)), canvas, SLOT(SetModelImage(QImage))); connect(drawTimer, SIGNAL(CurveReady()), this, SLOT(SetROCInfo())); expose = new Expose(canvas); import = new DataImporter(); connect(import, import->SetDataSignal(), this, SLOT(SetData(std::vector, ivec, std::vector, bool))); connect(import, import->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector))); connect(import, SIGNAL(SetDimensionNames(QStringList)), this, SLOT(SetDimensionNames(QStringList))); } void MLDemos::initPlugins() { qDebug() << "Importing plugins"; QDir pluginsDir = QDir(qApp->applicationDirPath()); QStringList pluginFileNames; QDir alternativeDir = pluginsDir; #if defined(Q_OS_WIN) if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") pluginsDir.cdUp(); #elif defined(Q_OS_MAC) if (pluginsDir.dirName() == "MacOS") { if(!pluginsDir.cd("plugins")) { qDebug() << "looking for alternative directory"; pluginsDir.cdUp(); pluginsDir.cdUp(); alternativeDir = pluginsDir; alternativeDir.cd("plugins"); } pluginsDir.cdUp(); } #endif bool bFoundPlugins = false; #if defined(DEBUG) qDebug() << "looking for debug plugins"; bFoundPlugins = pluginsDir.cd("pluginsDebug"); #else qDebug() << "looking for release plugins"; bFoundPlugins = pluginsDir.cd("plugins"); #endif if(!bFoundPlugins) { qDebug() << "plugins not found on: " << pluginsDir.absolutePath(); qDebug() << "using alternative directory: " << alternativeDir.absolutePath(); pluginsDir = alternativeDir; } foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); QObject *plugin = loader.instance(); if (plugin) { qDebug() << "loading " << fileName; // check type of plugin CollectionInterface *iCollection = qobject_cast(plugin); if(iCollection) { std::vector classifierList = iCollection->GetClassifiers(); std::vector clustererList = iCollection->GetClusterers(); std::vector regressorList = iCollection->GetRegressors(); std::vector dynamicalList = iCollection->GetDynamicals(); std::vector maximizerList = iCollection->GetMaximizers(); std::vector projectorList = iCollection->GetProjectors(); FOR(i, classifierList.size()) AddPlugin(classifierList[i], SLOT(ChangeActiveOptions)); FOR(i, clustererList.size()) AddPlugin(clustererList[i], SLOT(ChangeActiveOptions)); FOR(i, regressorList.size()) AddPlugin(regressorList[i], SLOT(ChangeActiveOptions)); FOR(i, dynamicalList.size()) AddPlugin(dynamicalList[i], SLOT(ChangeActiveOptions)); FOR(i, maximizerList.size()) AddPlugin(maximizerList[i], SLOT(ChangeActiveOptions)); FOR(i, projectorList.size()) AddPlugin(projectorList[i], SLOT(ChangeActiveOptions)); continue; } ClassifierInterface *iClassifier = qobject_cast(plugin); if (iClassifier) { AddPlugin(iClassifier, SLOT(ChangeActiveOptions())); continue; } ClustererInterface *iClusterer = qobject_cast(plugin); if (iClusterer) { AddPlugin(iClusterer, SLOT(ChangeActiveOptions())); continue; } RegressorInterface *iRegressor = qobject_cast(plugin); if (iRegressor) { AddPlugin(iRegressor, SLOT(ChangeActiveOptions())); continue; } DynamicalInterface *iDynamical = qobject_cast(plugin); if (iDynamical) { AddPlugin(iDynamical, SLOT(ChangeActiveOptions())); continue; } MaximizeInterface *iMaximize = qobject_cast(plugin); if (iMaximize) { AddPlugin(iMaximize, SLOT(ChangeActiveOptions())); continue; } ProjectorInterface *iProject = qobject_cast(plugin); if (iProject) { AddPlugin(iProject, SLOT(ChangeActiveOptions())); continue; } InputOutputInterface *iIO = qobject_cast(plugin); if (iIO) { AddPlugin(iIO); continue; } AvoidanceInterface *iAvoid = qobject_cast(plugin); if (iAvoid) { AddPlugin(iAvoid, SLOT(ChangeActiveOptions())); continue; } } else qDebug() << loader.errorString(); } } void MLDemos::SetTextFontSize() { #if defined(Q_OS_MAC) return; // default fontsizes are for mac already ;) #endif QFont font("Lucida Sans Unicode", 7); QList children = algorithmWidget->findChildren(); FOR(i, children.size()) { if(children[i]) children[i]->setFont(font); } optionsMaximize->gaussianButton->setFont(QFont("Lucida Sans Unicode", 18)); optionsMaximize->gradientButton->setFont(QFont("Lucida Sans Unicode", 18)); optionsMaximize->targetButton->setFont(QFont("Lucida Sans Unicode", 18)); } void MLDemos::ShowContextMenuSpray(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext1Widget->move(drawToolbar->sprayButton->mapToGlobal(pt)); drawContext1Widget->show(); drawContext1Widget->setFocus(); } void MLDemos::ShowContextMenuLine(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext2Widget->move(drawToolbar->lineButton->mapToGlobal(pt)); drawContext2Widget->show(); drawContext2Widget->setFocus(); } void MLDemos::ShowContextMenuEllipse(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext2Widget->move(drawToolbar->ellipseButton->mapToGlobal(pt)); drawContext2Widget->show(); drawContext2Widget->setFocus(); } void MLDemos::ShowContextMenuErase(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext1Widget->move(drawToolbar->eraseButton->mapToGlobal(pt)); drawContext1Widget->show(); drawContext1Widget->setFocus(); } void MLDemos::ShowContextMenuObstacle(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext3Widget->move(drawToolbar->obstacleButton->mapToGlobal(pt)); drawContext3Widget->show(); drawContext3Widget->setFocus(); } void MLDemos::ShowContextMenuReward(const QPoint &point) { QPoint pt = QPoint(30, 0); drawContext4Widget->move(drawToolbar->paintButton->mapToGlobal(pt)); drawContext4Widget->show(); drawContext4Widget->setFocus(); } bool IsChildOf(QObject *child, QObject *parent) { if(!parent || !child) return false; if(child == parent) return true; QList list = parent->children(); if(list.isEmpty()) return false; QList::iterator i; for (i = list.begin(); iisVisible()) { if(!IsChildOf(now, drawContext1Widget)) HideContextMenus(); } if(drawContext2Widget->isVisible()) { if(!IsChildOf(now, drawContext2Widget)) HideContextMenus(); } if(drawContext3Widget->isVisible()) { if(!IsChildOf(now, drawContext3Widget)) HideContextMenus(); } if(drawContext4Widget->isVisible()) { if(!IsChildOf(now, drawContext4Widget)) HideContextMenus(); } } void MLDemos::HideContextMenus() { drawContext1Widget->hide(); drawContext2Widget->hide(); drawContext3Widget->hide(); drawContext4Widget->hide(); } void MLDemos::AddPlugin(InputOutputInterface *iIO) { inputoutputs.push_back(iIO); bInputRunning.push_back(false); connect(this, SIGNAL(SendResults(std::vector)), iIO->object(), iIO->FetchResultsSlot()); connect(iIO->object(), iIO->SetDataSignal(), this, SLOT(SetData(std::vector, ivec, std::vector, bool))); connect(iIO->object(), iIO->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector))); connect(iIO->object(), iIO->QueryClassifierSignal(), this, SLOT(QueryClassifier(std::vector))); connect(iIO->object(), iIO->QueryRegressorSignal(), this, SLOT(QueryRegressor(std::vector))); connect(iIO->object(), iIO->QueryDynamicalSignal(), this, SLOT(QueryDynamical(std::vector))); connect(iIO->object(), iIO->QueryClustererSignal(), this, SLOT(QueryClusterer(std::vector))); connect(iIO->object(), iIO->QueryMaximizerSignal(), this, SLOT(QueryMaximizer(std::vector))); connect(iIO->object(), iIO->DoneSignal(), this, SLOT(DisactivateIO(QObject *))); QString name = iIO->GetName(); QAction *pluginAction = ui.menuInput_Output->addAction(name); pluginAction->setCheckable(true); pluginAction->setChecked(false); connect(pluginAction,SIGNAL(toggled(bool)), this, SLOT(ActivateIO())); QAction *importAction = ui.menuImport->addAction(name); importAction->setCheckable(true); importAction->setChecked(false); connect(importAction,SIGNAL(toggled(bool)), this, SLOT(ActivateImport())); } void MLDemos::AddPlugin(ClassifierInterface *iClassifier, const char *method) { if(!iClassifier) return; // we add the interface so we can use it to produce classifiers classifiers.push_back(iClassifier); // we add the classifier parameters to the gui optionsClassify->tabWidget->addTab(iClassifier->GetParameterWidget(), iClassifier->GetName()); } void MLDemos::AddPlugin(ClustererInterface *iCluster, const char *method) { if(!iCluster) return; clusterers.push_back(iCluster); optionsCluster->tabWidget->addTab(iCluster->GetParameterWidget(), iCluster->GetName()); } void MLDemos::AddPlugin(RegressorInterface *iRegress, const char *method) { if(!iRegress) return; regressors.push_back(iRegress); optionsRegress->tabWidget->addTab(iRegress->GetParameterWidget(), iRegress->GetName()); } void MLDemos::AddPlugin(DynamicalInterface *iDynamical, const char *method) { if(!iDynamical) return; dynamicals.push_back(iDynamical); optionsDynamic->tabWidget->addTab(iDynamical->GetParameterWidget(), iDynamical->GetName()); } void MLDemos::AddPlugin(AvoidanceInterface *iAvoid, const char *method) { if(!iAvoid) return; avoiders.push_back(iAvoid); optionsDynamic->obstacleCombo->addItem(iAvoid->GetName()); } void MLDemos::AddPlugin(MaximizeInterface *iMaximizer, const char *method) { if(!iMaximizer) return; maximizers.push_back(iMaximizer); optionsMaximize->tabWidget->addTab(iMaximizer->GetParameterWidget(), iMaximizer->GetName()); } void MLDemos::AddPlugin(ProjectorInterface *iProject, const char *method) { if(!iProject) return; projectors.push_back(iProject); optionsProject->tabWidget->addTab(iProject->GetParameterWidget(), iProject->GetName()); } MLDemos::~MLDemos() { Clear(); FOR(i, inputoutputs.size()) { if(inputoutputs[i] && bInputRunning[i]) inputoutputs[i]->Stop(); } SaveLayoutOptions(); delete optionsClassify; delete optionsRegress; delete optionsCluster; delete optionsDynamic; delete optionsMaximize; delete drawToolbar; delete drawToolbarContext1; delete drawToolbarContext2; delete displayOptions; canvas->hide(); delete canvas; } void MLDemos::closeEvent(QCloseEvent *event) { if (true) { mutex.lock(); DEL(regressor); DEL(classifier); mutex.unlock(); qApp->quit(); } else { event->ignore(); } } void MLDemos::resizeEvent( QResizeEvent *event ) { if(!canvas) return; if(canvas->canvasType) { CanvasOptionsChanged(); } else { } canvas->ResizeEvent(); CanvasMoveEvent(); } void MLDemos::AlgoChanged() { ChangeInfoFile(); actionAlgorithms->setChecked(algorithmWidget->isVisible()); if(algorithmOptions->tabMax->isVisible()) { drawToolbar->paintButton->setChecked(true); DrawPaint(); } if(algorithmOptions->tabDyn->isVisible()) { drawToolbar->trajectoryButton->setChecked(true); DrawTrajectory(); } if(algorithmOptions->tabRegr->isVisible() || algorithmOptions->tabClass->isVisible() || algorithmOptions->tabClust->isVisible()) { drawToolbar->sprayButton->setChecked(true); DrawSpray(); } } void MLDemos::CompareAdd() { if(algorithmOptions->tabClass->isVisible()) { int tab = optionsClassify->tabWidget->currentIndex(); QString name = classifiers[tab]->GetAlgoString(); QString parameterData; QTextStream stream(¶meterData, QIODevice::WriteOnly); stream << "Classification" << ":" << tab << "\n"; classifiers[tab]->SaveParams(stream); optionsCompare->algoList->addItem(name); compareOptions.push_back(parameterData); } if(algorithmOptions->tabRegr->isVisible()) { int tab = optionsRegress->tabWidget->currentIndex(); QString name = regressors[tab]->GetAlgoString(); QString parameterData; QTextStream stream(¶meterData, QIODevice::WriteOnly); stream << "Regression" << ":" << tab << "\n"; regressors[tab]->SaveParams(stream); optionsCompare->algoList->addItem(name); compareOptions.push_back(parameterData); } if(algorithmOptions->tabDyn->isVisible()) { int tab = optionsDynamic->tabWidget->currentIndex(); QString name = dynamicals[tab]->GetAlgoString(); QString parameterData; QTextStream stream(¶meterData, QIODevice::WriteOnly); stream << "Dynamical" << ":" << tab << "\n"; dynamicals[tab]->SaveParams(stream); optionsCompare->algoList->addItem(name); compareOptions.push_back(parameterData); } if(algorithmOptions->tabMax->isVisible()) { int tab = optionsMaximize->tabWidget->currentIndex(); QString name = maximizers[tab]->GetAlgoString(); QString parameterData; QTextStream stream(¶meterData, QIODevice::WriteOnly); stream << "Optimization" << ":" << tab << "\n"; maximizers[tab]->SaveParams(stream); optionsCompare->algoList->addItem(name); compareOptions.push_back(parameterData); } actionCompare->setChecked(true); compareWidget->show(); } void MLDemos::CompareClear() { optionsCompare->algoList->clear(); compareOptions.clear(); if(compareDisplay) compareDisplay->hide(); } void MLDemos::CompareRemove() { int offset = 0; FOR(i, optionsCompare->algoList->count()) { if(optionsCompare->algoList->item(i)->isSelected()) { compareOptions.removeAt(i-offset); offset++; } } QList selected = optionsCompare->algoList->selectedItems(); FOR(i, selected.size()) delete selected[i]; if(optionsCompare->algoList->count()) optionsCompare->algoList->item(0)->setSelected(true); } void MLDemos::ShowAlgorithmOptions() { if(actionAlgorithms->isChecked()) algorithmWidget->show(); else algorithmWidget->hide(); } void MLDemos::ShowOptionCompare() { if(actionCompare->isChecked()) { compareWidget->show(); } else { compareWidget->hide(); } } void MLDemos::ShowSampleDrawing() { if(actionDrawSamples->isChecked()) { drawToolbarWidget->show(); } else { drawToolbarWidget->hide(); } } void MLDemos::ShowOptionDisplay() { if(actionDisplayOptions->isChecked()) displayDialog->show(); else displayDialog->hide(); } void MLDemos::ShowToolbar() { if(ui.actionSmall_Icons->isChecked()) { toolBar->setIconSize(QSize(32,32)); toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); } else { toolBar->setIconSize(QSize(64,64)); toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); } if(ui.actionShow_Toolbar->isChecked()) toolBar->show(); else toolBar->hide(); } void MLDemos::ShowStatsDialog() { if(actionShowStats->isChecked()) statsDialog->show(); else statsDialog->hide(); } void MLDemos::ShowAbout() { about->show(); } void MLDemos::ManualSelection() { manualSelectDialog->show(); } void MLDemos::InputDimensions() { inputDimensionsDialog->show(); } void MLDemos::HideSampleDrawing() { drawToolbarWidget->hide(); actionDrawSamples->setChecked(false); } void MLDemos::HideOptionDisplay() { displayDialog->hide(); actionDisplayOptions->setChecked(false); } void MLDemos::HideToolbar() { toolBar->hide(); ui.actionShow_Toolbar->setChecked(false); } void MLDemos::HideStatsDialog() { statsDialog->hide(); actionShowStats->setChecked(false); } void MLDemos::Clear() { drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); qApp->processEvents(); DEL(classifier); DEL(regressor); DEL(dynamical); DEL(clusterer); DEL(maximizer); DEL(projector); canvas->maps.confidence = QPixmap(); canvas->maps.model = QPixmap(); canvas->maps.info = QPixmap(); canvas->liveTrajectory.clear(); canvas->repaint(); UpdateInfo(); } void MLDemos::ResetPositiveClass() { int labMin = INT_MAX, labMax = INT_MIN; if(!canvas->data->GetCount()) { labMin = 0; labMax = 1; } else { ivec labels = canvas->data->GetLabels(); FOR(i, labels.size()) { if(labels[i] > labMax) labMax = labels[i]; if(labels[i] < labMin) labMin = labels[i]; } } int dimCount = max(2,canvas->data->GetDimCount()); int currentOutputDim = optionsCompare->outputDimCombo->currentIndex(); optionsCompare->outputDimCombo->clear(); optionsRegress->outputDimCombo->clear(); FOR(i, dimCount) { if(i < canvas->dimNames.size()) { optionsCompare->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i))); optionsRegress->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i))); } else { optionsCompare->outputDimCombo->addItem(QString("%1").arg(i+1)); optionsRegress->outputDimCombo->addItem(QString("%1").arg(i+1)); } } if(currentOutputDim < dimCount) optionsCompare->outputDimCombo->setCurrentIndex(currentOutputDim); optionsClassify->positiveSpin->setRange(labMin,labMax); if(optionsClassify->positiveSpin->value() < labMin) optionsClassify->positiveSpin->setValue(labMin); else if(optionsClassify->positiveSpin->value() > labMax) optionsClassify->positiveSpin->setValue(labMax); ui.canvasX1Spin->setRange(1,dimCount); ui.canvasX2Spin->setRange(1,dimCount); ui.canvasX3Spin->setRange(0,dimCount); canvas->SetDim(ui.canvasX1Spin->value()-1,ui.canvasX2Spin->value()-1, ui.canvasX3Spin->value()-1); ManualSelectionUpdated(); InputDimensionsUpdated(); } void MLDemos::ChangeActiveOptions() { DisplayOptionChanged(); } void MLDemos::ClearData() { sourceData.clear(); sourceLabels.clear(); projectedData.clear(); if(canvas) { canvas->dimNames.clear(); canvas->sampleColors.clear(); canvas->data->Clear(); canvas->targets.clear(); canvas->maps.reward = QPixmap(); canvas->maps.samples = QPixmap(); canvas->maps.trajectories = QPixmap(); canvas->maps.grid = QPixmap(); } Clear(); ResetPositiveClass(); ManualSelectionUpdated(); UpdateInfo(); } void MLDemos::DrawSingle() { if(drawToolbar->singleButton->isChecked()) { drawToolbar->sprayButton->setChecked(false); drawToolbar->eraseButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawSpray() { if(drawToolbar->sprayButton->isChecked()) { drawToolbar->singleButton->setChecked(false); drawToolbar->eraseButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawErase() { if(drawToolbar->eraseButton->isChecked()) { drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawLine() { if(drawToolbar->lineButton->isChecked()) { drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->eraseButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawEllipse() { if(drawToolbar->ellipseButton->isChecked()) { drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->eraseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawTrajectory() { if(drawToolbar->trajectoryButton->isChecked()) { drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->eraseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawObstacle() { if(drawToolbar->obstacleButton->isChecked()) { drawToolbar->eraseButton->setChecked(false); drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->paintButton->setChecked(false); } } void MLDemos::DrawPaint() { if(drawToolbar->paintButton->isChecked()) { drawToolbar->eraseButton->setChecked(false); drawToolbar->singleButton->setChecked(false); drawToolbar->sprayButton->setChecked(false); drawToolbar->ellipseButton->setChecked(false); drawToolbar->lineButton->setChecked(false); drawToolbar->trajectoryButton->setChecked(false); drawToolbar->obstacleButton->setChecked(false); } } void MLDemos::AvoidOptionChanged() { if(dynamical) { int avoidIndex = optionsDynamic->obstacleCombo->currentIndex(); mutex.lock(); if(dynamical->avoid) delete dynamical->avoid; if(!avoidIndex) dynamical->avoid = 0; else dynamical->avoid = avoiders[avoidIndex-1]->GetObstacleAvoidance(); mutex.unlock(); drawTimer->Stop(); drawTimer->Clear(); drawTimer->start(QThread::NormalPriority); } } void MLDemos::ColorMapChanged() { if(dynamical) { drawTimer->Stop(); drawTimer->Clear(); drawTimer->bColorMap = optionsDynamic->colorCheck->isChecked(); drawTimer->start(QThread::NormalPriority); } } void MLDemos::DisplayOptionChanged() { if(!canvas) return; canvas->bDisplayInfo = displayOptions->infoCheck->isChecked(); canvas->bDisplayLearned = displayOptions->modelCheck->isChecked(); canvas->bDisplayMap = displayOptions->mapCheck->isChecked(); canvas->bDisplaySamples = displayOptions->samplesCheck->isChecked(); canvas->bDisplayTrajectories = displayOptions->samplesCheck->isChecked(); canvas->bDisplayTimeSeries = displayOptions->samplesCheck->isChecked(); canvas->bDisplayGrid = displayOptions->gridCheck->isChecked(); { int xIndex = ui.canvasX1Spin->value()-1; int yIndex = ui.canvasX2Spin->value()-1; int zIndex = ui.canvasX3Spin->value()-1; canvas->SetDim(xIndex, yIndex, zIndex); } float zoom = displayOptions->spinZoom->value(); if(zoom >= 0.f) zoom += 1.f; else zoom = 1.f / (fabs(zoom)+1.f); if(zoom != canvas->GetZoom()) { drawTimer->Stop(); drawTimer->Clear(); canvas->SetZoom(zoom); if(!canvas->canvasType) { QMutexLocker lock(&mutex); if(classifier) { classifiers[tabUsedForTraining]->Draw(canvas, classifier); if(classifier->UsesDrawTimer()) { drawTimer->start(QThread::NormalPriority); } } else if(regressor) { regressors[tabUsedForTraining]->Draw(canvas, regressor); //drawTimer->start(QThread::NormalPriority); } else if(clusterer) { clusterers[tabUsedForTraining]->Draw(canvas, clusterer); drawTimer->start(QThread::NormalPriority); } else if(dynamical) { dynamicals[tabUsedForTraining]->Draw(canvas, dynamical); if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority); } else if(maximizer) { drawTimer->start(QThread::NormalPriority); } else if(projector) { projectors[tabUsedForTraining]->Draw(canvas, projector); } } canvas->repaint(); } // canvas->bDisplayTrajectories = displayOptions->trajectoriesCheck->isChecked(); if(optionsDynamic) { canvas->trajectoryCenterType = optionsDynamic->centerCombo->currentIndex(); canvas->trajectoryResampleType = optionsDynamic->resampleCombo->currentIndex(); canvas->trajectoryResampleCount = optionsDynamic->resampleSpin->value(); } CanvasTypeChanged(); CanvasOptionsChanged(); canvas->ResetSamples(); canvas->repaint(); } void MLDemos::ChangeInfoFile() { QString infoFile; if(algorithmOptions->tabClass->isVisible()) { int tab = optionsClassify->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)classifiers.size() || !classifiers[tab]) return; infoFile = classifiers[tab]->GetInfoFile(); } if(algorithmOptions->tabClust->isVisible()) { int tab = optionsCluster->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)clusterers.size() || !clusterers[tab]) return; infoFile = clusterers[tab]->GetInfoFile(); } if(algorithmOptions->tabRegr->isVisible()) { int tab = optionsRegress->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)regressors.size() || !regressors[tab]) return; infoFile = regressors[tab]->GetInfoFile(); } if(algorithmOptions->tabDyn->isVisible()) { int tab = optionsDynamic->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)dynamicals.size() || !dynamicals[tab]) return; infoFile = dynamicals[tab]->GetInfoFile(); } if(algorithmOptions->tabMax->isVisible()) { int tab = optionsMaximize->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)maximizers.size() || !maximizers[tab]) return; infoFile = maximizers[tab]->GetInfoFile(); } if(algorithmOptions->tabProj->isVisible()) { int tab = optionsProject->tabWidget->currentIndex(); if(tab < 0 || tab >= (int)projectors.size() || !projectors[tab]) return; infoFile = projectors[tab]->GetInfoFile(); } if(infoFile == "") infoFile = "mldemos.html"; // we want the main information page QDir helpDir = QDir(qApp->applicationDirPath()); QDir alternativeDir = helpDir; #if defined(Q_OS_WIN) if (helpDir.dirName().toLower() == "debug" || helpDir.dirName().toLower() == "release") helpDir.cdUp(); #elif defined(Q_OS_MAC) if (helpDir.dirName() == "MacOS") { if(!helpDir.cd("help")) { helpDir.cdUp(); helpDir.cdUp(); helpDir.cdUp(); alternativeDir = helpDir; } else helpDir.cdUp(); } #endif if(!helpDir.cd("help")) { //qDebug() << "using alternative directory: " << alternativeDir.absolutePath(); helpDir = alternativeDir; if(!helpDir.cd("help")) return; } //qDebug() << "using help directory: " << helpDir.absolutePath(); QString filePath(helpDir.absolutePath() + "/" + infoFile); //qDebug() << "loading info from: " << filePath; showStats->algoText->clear(); showStats->algoText->setSource(QUrl::fromLocalFile(filePath)); } void MLDemos::ManualSelectionUpdated() { if(!canvas) return; // we add the samples vector samples = canvas->data->GetSamples(); int dim = samples.size() ? samples[0].size() : 0; ivec labels = canvas->data->GetLabels(); manualSelection->sampleList->clear(); FOR(i, samples.size()) { QString item = QString("%1: (%2)").arg(i+1).arg(labels[i]); FOR(d, dim) item += QString(" %1").arg(samples[i][d], 0, 'f', 2); manualSelection->sampleList->addItem(item); } ManualSelectionChanged(); } void MLDemos::ManualSelectionChanged() { int count = manualSelection->sampleList->count(); int trainCount = count, testCount = 0; QList selected = manualSelection->sampleList->selectedItems(); if(selected.size()) { trainCount = selected.size(); testCount = count - trainCount; } manualSelection->TrainLabel->setText(QString("Train: %1").arg(trainCount)); manualSelection->TestLabel->setText(QString("Test: %1").arg(testCount)); } void MLDemos::ManualSelectionClear() { manualSelection->sampleList->clearSelection(); ManualSelectionChanged(); } void MLDemos::ManualSelectionInvert() { FOR(i, manualSelection->sampleList->count()) { manualSelection->sampleList->item(i)->setSelected(!manualSelection->sampleList->item(i)->isSelected()); } ManualSelectionChanged(); } void MLDemos::ManualSelectionRandom() { float ratio = (manualSelection->randomCombo->currentIndex()+1.f)/10.f; manualSelection->sampleList->clearSelection(); u32* perm = randPerm(manualSelection->sampleList->count()); FOR(i, ratio*manualSelection->sampleList->count()) { manualSelection->sampleList->item(perm[i])->setSelected(true); } KILL(perm); ManualSelectionChanged(); } void MLDemos::ManualSelectionRemove() { if(!canvas || !canvas->data->GetCount()) return; QList selected = manualSelection->sampleList->selectedItems(); if(!selected.size()) return; ivec removeList(selected.count()); FOR(i, selected.count()) { removeList[i] = manualSelection->sampleList->row(selected[i]); } canvas->data->RemoveSamples(removeList); if(canvas->sampleColors.size() && removeList.size() < canvas->sampleColors.size()) { int offset = 0; FOR(i, removeList.size()) { int index = i - offset; if(index < 0 || index >= canvas->sampleColors.size()) continue; canvas->sampleColors.erase(canvas->sampleColors.begin()+index); offset++; } } ManualSelectionUpdated(); ManualSelectionChanged(); canvas->ResetSamples(); CanvasOptionsChanged(); canvas->repaint(); } void MLDemos::InputDimensionsUpdated() { if(!canvas) return; int dim = canvas->data->GetDimCount(); inputDimensions->dimList->clear(); fvec xMin(dim,FLT_MAX), xMax(dim,-FLT_MAX); vector samples = canvas->data->GetSamples(); FOR(i, samples.size()) { FOR(d, dim) { xMin[d] = min(xMin[d], samples[i][d]); xMax[d] = max(xMax[d], samples[i][d]); } } FOR(d, dim) { QString item = QString("%1").arg(d+1); if(d < canvas->dimNames.size()) item += QString(") %2").arg(canvas->dimNames.at(d)); item += QString(" : [%1 --> %2]").arg(xMin[d], 0, 'f', 3).arg(xMax[d], 0, 'f', 3); inputDimensions->dimList->addItem(item); } ManualSelectionChanged(); } void MLDemos::InputDimensionsChanged() { int count = inputDimensions->dimList->count(); QList selected = inputDimensions->dimList->selectedItems(); inputDimensions->TrainLabel->setText(QString("Used: %1").arg(selected.size())); inputDimensions->TestLabel->setText(QString("Unused: %1").arg(count-selected.size())); } void MLDemos::InputDimensionsClear() { inputDimensions->dimList->clearSelection(); ManualSelectionChanged(); } void MLDemos::InputDimensionsInvert() { FOR(i, inputDimensions->dimList->count()) { inputDimensions->dimList->item(i)->setSelected(!inputDimensions->dimList->item(i)->isSelected()); } ManualSelectionChanged(); } void MLDemos::InputDimensionsRandom() { float ratio = (inputDimensions->randomCombo->currentIndex()+1.f)/10.f; inputDimensions->dimList->clearSelection(); u32* perm = randPerm(inputDimensions->dimList->count()); FOR(i, ratio*inputDimensions->dimList->count()) { inputDimensions->dimList->item(perm[i])->setSelected(true); } KILL(perm); ManualSelectionChanged(); } void MLDemos::DrawCrosshair() { int drawType = 0; if(drawToolbar->singleButton->isChecked()) drawType = 1; if(drawToolbar->sprayButton->isChecked()) drawType = 2; if(drawToolbar->eraseButton->isChecked()) drawType = 3; if(drawToolbar->ellipseButton->isChecked()) drawType = 4; if(drawToolbar->lineButton->isChecked()) drawType = 5; if(drawToolbar->trajectoryButton->isChecked()) drawType = 6; if(drawToolbar->obstacleButton->isChecked()) drawType = 7; if(drawToolbar->paintButton->isChecked()) drawType = 8; if(!drawType || drawType == 1 || drawType == 6) { canvas->crosshair = QPainterPath(); canvas->bNewCrosshair = false; return; } int type = drawToolbarContext1->randCombo->currentIndex(); float aX = drawToolbarContext2->spinSigmaX->value(); float aY = drawToolbarContext2->spinSigmaY->value(); float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf; float s = drawToolbarContext1->spinSize->value(); int size = (int)(s*canvas->height()); int sizeX = (int)(aX*canvas->height()); int Size = canvas->height(); QPainterPath cursor; float sin_angle = sinf(angle); float cos_angle = cosf(angle); switch(drawType) { case 5: // line { QPointF pStart, pStop; float x = cos_angle*aX; float y = sin_angle*aX; pStart = QPointF(- x*Size, - y*Size); pStop = QPointF(+ x*Size, + y*Size); cursor.moveTo(pStart); cursor.lineTo(pStop); canvas->crosshair = cursor; canvas->bNewCrosshair = false; return; } break; case 2: // spray case 3: // erase { cursor.addEllipse(QPoint(0,0),size/2,size/2); canvas->crosshair = cursor; canvas->bNewCrosshair = false; return; } break; case 7: // obstacles { Obstacle o; o.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf; o.axes.resize(2); o.axes[0] = drawToolbarContext3->spinSigmaX->value(); o.axes[1] = drawToolbarContext3->spinSigmaY->value(); o.power[0] = drawToolbarContext3->spinPowerX->value(); o.power[1] = drawToolbarContext3->spinPowerY->value(); o.repulsion[0] = drawToolbarContext3->spinRepulsionX->value(); o.repulsion[1] = drawToolbarContext3->spinRepulsionY->value(); o.center = fVec(0,0); canvas->crosshair = canvas->DrawObstacle(o); canvas->bNewCrosshair = false; return; } break; case 8: // paint { float radius = drawToolbarContext4->spinRadius->value(); QPainterPath cursor; cursor.addEllipse(QPoint(0,0),radius,radius); canvas->crosshair = cursor; canvas->bNewCrosshair = false; return; } break; } QPointF oldPoint, point; for(float theta=0; theta < 2*PIf + 0.1; theta += 0.1f) { float X, Y; if(drawType == 2 || drawType == 3) { X = sqrtf(aX)/2 * cosf(theta); Y = sqrtf(aY)/2 * sinf(theta); } else { X = aX * cosf(theta); Y = aY * sinf(theta); } float RX = + X * cos_angle + Y * sin_angle; float RY = - X * sin_angle + Y * cos_angle; point = QPointF(RX*Size,RY*Size); if(theta==0) { cursor.moveTo(point); continue; } cursor.lineTo(point); oldPoint = point; } canvas->crosshair = cursor; canvas->bNewCrosshair = false; } void MLDemos::Drawing( fvec sample, int label) { if(canvas->canvasType) return; int drawType = 0; // none if(drawToolbar->singleButton->isChecked()) drawType = 1; if(drawToolbar->sprayButton->isChecked()) drawType = 2; if(drawToolbar->eraseButton->isChecked()) drawType = 3; if(drawToolbar->ellipseButton->isChecked()) drawType = 4; if(drawToolbar->lineButton->isChecked()) drawType = 5; if(drawToolbar->trajectoryButton->isChecked()) drawType = 6; if(drawToolbar->obstacleButton->isChecked()) drawType = 7; if(drawToolbar->paintButton->isChecked()) drawType = 8; if(!drawType) return; int speed = 6; if(label) label = drawToolbar->classSpin->value(); switch(drawType) { case 1: // single samples { // we don't want to draw too often if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing canvas->data->AddSample(sample, label); } break; case 2: // spray samples { // we don't want to draw too often if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing int type = drawToolbarContext1->randCombo->currentIndex(); float s = drawToolbarContext1->spinSize->value(); float size = s*canvas->height(); int count = drawToolbarContext1->spinCount->value(); QPointF sampleCoords = canvas->toCanvasCoords(sample); // we generate the new data float variance = sqrtf(size*size/9.f*0.5f); fvec newSample; newSample.resize(2,0); FOR(i, count) { if(type == 0) // uniform { newSample[0] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.x(); newSample[1] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.y(); } else // normal { newSample[0] = RandN((float)sampleCoords.x(), variance); newSample[1] = RandN((float)sampleCoords.y(), variance); } fvec canvasSample = canvas->toSampleCoords(newSample[0],newSample[1]); //canvasSample.push_back(label ? RandN(1.f,0.5f) : RandN(-1.f,0.5f)); //canvasSample.push_back(label ? RandN(-.5f,0.5f) : RandN(.5f,0.5f)); canvas->data->AddSample(canvasSample, label); } } break; case 3: // erase { float s = drawToolbarContext1->spinSize->value(); float size = s*canvas->height(); QPointF center = canvas->toCanvasCoords(sample); bool anythingDeleted = canvas->DeleteData(center, size/2); if(anythingDeleted) { drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); if(dynamical && dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles()); drawTimer->start(QThread::NormalPriority); canvas->ResetSamples(); } } break; case 4: // ellipse { if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing float aX = drawToolbarContext2->spinSigmaX->value(); float aY = drawToolbarContext2->spinSigmaY->value(); float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf; int count = drawToolbarContext1->spinCount->value()+1; float sin_angle = sinf(angle); float cos_angle = cosf(angle); QPointF oldPoint, point; float startTheta = rand()/(float)RAND_MAX*2*PIf; for(float theta=0; theta < 2*PIf; theta += 2.f*PIf/count) { float X = aX * cosf(theta+startTheta); float Y = aY * sinf(theta+startTheta); float RX = + X * cos_angle + Y * sin_angle; float RY = - X * sin_angle + Y * cos_angle; fvec newSample; newSample.resize(2,0); newSample[0] = sample[0] + RX; newSample[1] = sample[1] + RY; if(theta==0) { oldPoint = point; continue; } canvas->data->AddSample(newSample, label); oldPoint = point; } } break; case 5: // line { if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing float aX = drawToolbarContext2->spinSigmaX->value(); float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf; int count = drawToolbarContext1->spinCount->value(); float sin_angle = sinf(angle); float cos_angle = cosf(angle); QPointF pStart, pStop; float x = cos_angle*aX; float y = sin_angle*aX; pStart = QPointF(sample[0] - x, sample[1] - y); pStop = QPointF(sample[0] + x, sample[1] + y); QPointF oldPoint = pStart; float start = (rand() / (float)RAND_MAX - 0.5) * (1/(float)count); FOR(i,count) { QPointF point = (pStop - pStart)*((i+1)/(float)count + start) + pStart; fvec newSample; newSample.resize(2); newSample[0] = point.x(); newSample[1] = point.y(); canvas->data->AddSample(newSample, label); oldPoint = point; } } break; case 6: // trajectory { if(trajectory.first == -1) // we're starting a trajectory { trajectory.first = canvas->data->GetCount(); } // we don't want to draw too often //if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing canvas->data->AddSample(sample, label, _TRAJ); trajectory.second = canvas->data->GetCount()-1; } break; case 7: // obstacle { bNewObstacle = true; obstacle = Obstacle(); obstacle.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf; obstacle.power[0] = drawToolbarContext3->spinPowerX->value(); obstacle.power[1] = drawToolbarContext3->spinPowerY->value(); obstacle.center = sample; obstacle.axes[0] = drawToolbarContext3->spinSigmaX->value(); obstacle.axes[1] = drawToolbarContext3->spinSigmaY->value(); obstacle.repulsion[0] = drawToolbarContext3->spinRepulsionX->value(); obstacle.repulsion[1] = drawToolbarContext3->spinRepulsionX->value(); } break; case 8: // paint rewards { float radius = drawToolbarContext4->spinRadius->value(); float alpha = drawToolbarContext4->spinAlpha->value(); canvas->PaintReward(sample, radius, label ? alpha : -alpha); /* // if we need to initialize the reward map if(!canvas->data->GetReward()->rewards) { ivec size; size.resize(2, 64); int length = size[0]*size[1]; float *values = new float[length]; FOR(i, length) values[i] = rand()/(float)RAND_MAX - 0.5f; canvas->data->GetReward()->SetReward(values, size, canvas->canvasTopLeft(), canvas->canvasBottomRight()); delete [] values; } canvas->data->GetReward()->ShiftValueAt(sample, 0.2, label ? 0.33 : -0.33); //qDebug() << canvas->data->GetReward()->ValueAt(sample); */ } break; } canvas->repaint(); drawTime.restart(); ResetPositiveClass(); ManualSelectionUpdated(); UpdateInfo(); } void MLDemos::DrawingStopped() { if(trajectory.first != -1) { // the last point is a duplicate, we take it out canvas->data->AddSequence(trajectory); canvas->drawnTrajectories = 0; trajectory.first = -1; canvas->repaint(); } if(bNewObstacle) { bNewObstacle = false; canvas->data->AddObstacle(obstacle); canvas->repaint(); if(dynamical && dynamical->avoid) { drawTimer->Stop(); drawTimer->Clear(); drawTimer->start(QThread::NormalPriority); } } } void MLDemos::ExposeData() { if(!expose) return; if(!canvas->data->GetCount()) return; // if(!canvas->data->GetSamples()[0].size() <= 2) return; expose->show(); expose->repaint(); } void MLDemos::FitToData() { canvas->FitToData(); float zoom = canvas->GetZoom(); if(zoom >= 1) zoom -=1; else zoom = 1/(-zoom) - 1; if(zoom == displayOptions->spinZoom->value()) { DisplayOptionChanged(); return; } displayOptions->spinZoom->blockSignals(true); displayOptions->spinZoom->setValue(zoom); displayOptions->spinZoom->blockSignals(false); drawTimer->Stop(); drawTimer->Clear(); if(!canvas->canvasType) { QMutexLocker lock(&mutex); if(classifier) { classifiers[tabUsedForTraining]->Draw(canvas, classifier); if(classifier->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority); } else if(regressor) { regressors[tabUsedForTraining]->Draw(canvas, regressor); //drawTimer->start(QThread::NormalPriority); } else if(clusterer) { clusterers[tabUsedForTraining]->Draw(canvas, clusterer); drawTimer->start(QThread::NormalPriority); } else if(dynamical) { dynamicals[tabUsedForTraining]->Draw(canvas, dynamical); if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority); } else if(projector) { projectors[tabUsedForTraining]->Draw(canvas, projector); } } DisplayOptionChanged(); } void MLDemos::CanvasMoveEvent() { if(canvas->canvasType) return; drawTimer->Stop(); drawTimer->Clear(); UpdateLearnedModel(); QMutexLocker lock(&mutex); if(classifier) { classifiers[tabUsedForTraining]->Draw(canvas, classifier); if(classifier->UsesDrawTimer()) { drawTimer->start(QThread::NormalPriority); } } else if(regressor) { regressors[tabUsedForTraining]->Draw(canvas, regressor); //drawTimer->start(QThread::NormalPriority); } else if(clusterer) { clusterers[tabUsedForTraining]->Draw(canvas, clusterer); drawTimer->start(QThread::NormalPriority); } else if(dynamical) { dynamicals[tabUsedForTraining]->Draw(canvas, dynamical); if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority); } else if(projector) { projectors[tabUsedForTraining]->Draw(canvas, projector); } canvas->repaint(); } void MLDemos::ZoomChanged(float d) { displayOptions->spinZoom->setValue(displayOptions->spinZoom->value()+d/4); } void MLDemos::CanvasTypeChanged() { bool bProjected = canvas->data->bProjected; int type = ui.canvasTypeCombo->currentIndex(); ui.canvasZoomSlider->setEnabled(false); ui.canvasZoomSlider->hide(); ui.canvasAxesWidget->hide(); switch(type) { case 0: // standard ui.canvasAxesWidget->show(); ui.canvasX3Spin->setEnabled(false); ui.canvasX1Label->setText(bProjected ? "e1" : "x1"); ui.canvasX2Label->setText(bProjected ? "e2" : "x2"); break; case 1: // scatterplot ui.canvasZoomSlider->show(); ui.canvasZoomSlider->setEnabled(true); break; case 2: // parallel coords break; case 3: // radial graph (radviz) break; case 4: // andrews plots break; case 5: // bubble plots ui.canvasAxesWidget->show(); ui.canvasX3Spin->setEnabled(true); ui.canvasX1Label->setText(bProjected ? "e1" : "x1"); ui.canvasX2Label->setText(bProjected ? "e2" : "x2"); break; } ui.canvasZoomSlider->setEnabled(ui.canvasTypeCombo->currentIndex() == 1); if(canvas->canvasType == ui.canvasTypeCombo->currentIndex()) return; canvas->SetCanvasType(ui.canvasTypeCombo->currentIndex()); CanvasOptionsChanged(); UpdateLearnedModel(); canvas->repaint(); } void MLDemos::CanvasOptionsChanged() { float zoom = 1.f + ui.canvasZoomSlider->value()/10.f; QSizePolicy policy = ui.canvasWidget->sizePolicy(); int dims = canvas ? (canvas->data->GetCount() ? canvas->data->GetSample(0).size() : 2) : 2; int w = ui.canvasArea->width(); int h = ui.canvasArea->height(); bool bNeedsZoom = false; if(h/dims < 100) { h = 100*dims; bNeedsZoom = true; } if(w/dims < 100) { w = 100*dims; bNeedsZoom = true; } if(canvas->canvasType != 1 || (!bNeedsZoom && zoom == 1.f)) { policy.setHorizontalPolicy(QSizePolicy::Preferred); policy.setVerticalPolicy(QSizePolicy::Preferred); ui.canvasWidget->setSizePolicy(policy); ui.canvasWidget->setMinimumSize(ui.canvasArea->size()); ui.canvasWidget->resize(ui.canvasArea->size()); canvas->resize(ui.canvasWidget->size()); ui.canvasArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui.canvasArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); canvas->SetCanvasType(canvas->canvasType); canvas->ResizeEvent(); return; } policy.setHorizontalPolicy(QSizePolicy::Fixed); policy.setVerticalPolicy(QSizePolicy::Fixed); ui.canvasWidget->setSizePolicy(policy); ui.canvasWidget->setMinimumSize(w*zoom,h*zoom); ui.canvasWidget->resize(w*zoom,h*zoom); canvas->resize(ui.canvasWidget->size()); ui.canvasArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); ui.canvasArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); canvas->SetCanvasType(canvas->canvasType); if(!canvas->canvasType) { QMutexLocker lock(&mutex); if(classifier) { classifiers[tabUsedForTraining]->Draw(canvas, classifier); } else if(regressor) { regressors[tabUsedForTraining]->Draw(canvas, regressor); } else if(clusterer) { clusterers[tabUsedForTraining]->Draw(canvas, clusterer); } else if(dynamical) { dynamicals[tabUsedForTraining]->Draw(canvas, dynamical); } else if(maximizer) { } else if(projector) { projectors[tabUsedForTraining]->Draw(canvas, projector); } } canvas->ResizeEvent(); } void MLDemos::Navigation( fvec sample ) { if(sample[0]==-1) { ZoomChanged(sample[1]); return; } QString information; char string[255]; int count = canvas->data->GetCount(); int pcount = 0, ncount = 0; ivec labels = canvas->data->GetLabels(); FOR(i, labels.size()) { if(labels[i] == 0) ++pcount; else ++ncount; } sprintf(string, "samples: %d (o:%.3d|x:%.3d)", count, pcount, ncount); information += QString(string); sprintf(string, " | x%d: %.3f x%d: %.3f", canvas->xIndex+1, sample[canvas->xIndex], canvas->yIndex+1, sample[canvas->yIndex]); information += QString(string); mutex.tryLock(500); if(classifier) { float score; if(classifier->IsMultiClass()) { fvec res = classifier->TestMulti(sample); int max = 0; FOR(i, res.size()) if(res[max] < res[i]) max = i; score = classifier->inverseMap[max]; } else { score = classifier->Test(sample); } drawTimer->bPaused = false; sprintf(string, " | value: %.4f", score); information += QString(string); } else if(dynamical) { // we build the trajectory(by hand) int count = 1000; std::vector trajectory; fvec position = sample; if(dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles()); FOR(i, count) { trajectory.push_back(position); fvec velocity = dynamical->Test(position); if(dynamical->avoid) { fvec newVelocity = dynamical->avoid->Avoid(position, velocity); velocity = newVelocity; } position += velocity*dynamical->dT; if(velocity == 0) break; } canvas->liveTrajectory = trajectory; canvas->repaint(); } mutex.unlock(); ui.statusBar->showMessage(information); } void MLDemos::TargetButton() { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setText("Target"); drag->setMimeData(mimeData); QPixmap pixmap(33,33); pixmap.fill(); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(Qt::black, 1.5)); painter.setBrush(Qt::NoBrush); int pad = 4, radius = 8; painter.drawEllipse(QPoint(16,16), radius, radius); painter.setBrush(Qt::black); painter.drawLine(QPoint(16,16) - QPoint(radius,radius), QPoint(16,16) - QPoint(radius+pad,radius+pad)); painter.drawLine(QPoint(16,16) + QPoint(radius,radius), QPoint(16,16) + QPoint(radius+pad,radius+pad)); painter.drawLine(QPoint(16,16) - QPoint(radius,-radius), QPoint(16,16) - QPoint(radius+pad,-radius-pad)); painter.drawLine(QPoint(16,16) + QPoint(radius,-radius), QPoint(16,16) + QPoint(radius+pad,-radius-pad)); drag->setPixmap(pixmap); drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2)); // maximization only allows one target, so we take the others out if(algorithmOptions->tabMax->isVisible()) { canvas->targets.clear(); canvas->repaint(); } Qt::DropAction dropAction = drag->exec(); } void MLDemos::GaussianButton() { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setText("Gaussian"); mimeData->setColorData(QVariant(optionsMaximize->varianceSpin->value())); drag->setMimeData(mimeData); QPixmap pixmap(33,33); pixmap.fill(); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(Qt::black, 1.5)); painter.setBrush(Qt::NoBrush); painter.drawEllipse(QPoint(16,16), 12,12); painter.setBrush(Qt::black); painter.drawEllipse(QPoint(16,16), 1,1); drag->setPixmap(pixmap); drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2)); Qt::DropAction dropAction = drag->exec(); } void MLDemos::GradientButton() { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setText("Gradient"); drag->setMimeData(mimeData); QPixmap pixmap(33,33); pixmap.fill(); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(Qt::black, 1.5)); painter.setBrush(Qt::NoBrush); painter.drawLine(QPoint(4,16), QPoint(29,4)); painter.drawLine(QPoint(4,16), QPoint(29,29)); painter.drawLine(QPoint(29,4), QPoint(29,29)); drag->setPixmap(pixmap); drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2)); Qt::DropAction dropAction = drag->exec(); } void MLDemos::BenchmarkButton() { int w = canvas->width(), h = canvas->height(); int type = optionsMaximize->benchmarkCombo->currentIndex(); QImage image(w, h, QImage::Format_ARGB32); image.fill(qRgb(255,255,255)); int dim = 2; float minSpace = 0.f; float maxSpace = 1.f; float minVal = FLT_MAX; float maxVal = -FLT_MAX; switch(type) { case 0: // griewangk minSpace = -60.f; maxSpace = 60.f; minVal = 0; maxVal = 2; break; case 1: // rastragin minSpace = -5.12f; maxSpace = 5.12f; minVal = 0; maxVal = 82; break; case 2: // schwefel minSpace = -500.f; maxSpace = 500.f; minVal = -838; maxVal = 838; break; case 3: // ackley minSpace = -2.f; maxSpace = 2.f; minVal = 0; maxVal = 2.3504; case 4: // michalewicz minSpace = -2; maxSpace = 2; minVal = -1.03159; maxVal = 5.74; // minVal = -1.03159; // maxVal = 55.74; } bool bSetValues = minVal == FLT_MAX; Eigen::VectorXd x(2); fVec point; float value = 0; FOR(i, w) { x[0] = i/(float)w*(maxSpace - minSpace) + minSpace; FOR(j, h) { x[1] = j/(float)h*(maxSpace - minSpace) + minSpace; switch(type) { case 0: value = griewangk(x)(0); break; case 1: value = rastragin(x)(0); break; case 2: value = schwefel(x)(0); break; case 3: value = ackley(x)(0); break; case 4: value = sixhump(x)(0); break; } if(bSetValues) { if(value < minVal) minVal = value; if(value > maxVal) maxVal = value; } else { value = (value-minVal)/(maxVal-minVal); } int color = 255.f*max(0.f,min(1.f,value)); image.setPixel(i,j,qRgba(255, color, color, 255)); } } if(bSetValues) qDebug() << "minmax: " << minVal << " " << maxVal; canvas->maps.reward = QPixmap::fromImage(image); canvas->repaint(); } void MLDemos::SaveData() { if(!canvas) return; QString filename = QFileDialog::getSaveFileName(this, tr("Save Data"), "", tr("ML Files (*.ml)")); if(filename.isEmpty()) return; if(!filename.endsWith(".ml")) filename += ".ml"; Save(filename); } void MLDemos::Save(QString filename) { QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { ui.statusBar->showMessage("WARNING: Unable to save file"); return; } file.close(); canvas->data->Save(filename.toAscii()); if(!canvas->maps.reward.isNull()) canvas->maps.reward.toImage().save(filename + "-reward.png"); SaveParams(filename); ui.statusBar->showMessage("Data saved successfully"); } void MLDemos::LoadData() { if(!canvas) return; QString filename = QFileDialog::getOpenFileName(this, tr("Load Data"), "", tr("ML Files (*.ml)")); if(filename.isEmpty()) return; if(!filename.endsWith(".ml")) filename += ".ml"; Load(filename); } void MLDemos::Load(QString filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { ui.statusBar->showMessage("WARNING: Unable to open file"); return; } file.close(); ClearData(); canvas->data->Load(filename.toAscii()); LoadParams(filename); QImage reward(filename + "-reward.png"); if(!reward.isNull()) canvas->maps.reward = QPixmap::fromImage(reward); ui.statusBar->showMessage("Data loaded successfully"); ResetPositiveClass(); ManualSelectionUpdated(); UpdateInfo(); canvas->repaint(); } void MLDemos::ImportData() { if(!canvas || !import) return; QString filename = QFileDialog::getOpenFileName(this, tr("Import Data Data"), "", tr("Dataset Files (*.csv *.data *.txt)")); if(filename.isEmpty()) return; import->Start(); import->Parse(filename); import->SendData(); } void MLDemos::ImportData(QString filename) { import->Start(); import->Parse(filename); import->SendData(); if(import->GetHeaders().size()) canvas->dimNames = import->GetHeaders(); ui.statusBar->showMessage("Data loaded successfully"); } void MLDemos::dragEnterEvent(QDragEnterEvent *event) { QList dragUrl; if(event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); QStringList dataType; dataType << ".ml" << ".csv" << ".data"; for(int i=0; iacceptProposedAction(); } } } void MLDemos::dropEvent(QDropEvent *event) { if(!event->mimeData()->hasUrls()) return; FOR(i, event->mimeData()->urls().length()) { QString filename = event->mimeData()->urls()[i].toLocalFile(); qDebug() << "accepted drop file:" << filename; if(filename.toLower().endsWith(".ml")) { ClearData(); canvas->data->Load(filename.toAscii()); LoadParams(filename); ui.statusBar->showMessage("Data loaded successfully"); ResetPositiveClass(); ManualSelectionUpdated(); UpdateInfo(); canvas->repaint(); } else if(filename.toLower().endsWith(".csv") || filename.toLower().endsWith(".data")) { ClearData(); ImportData(filename); ResetPositiveClass(); ManualSelectionUpdated(); UpdateInfo(); canvas->repaint(); } } event->acceptProposedAction(); } void MLDemos::ExportSVG() { QString filename = QFileDialog::getSaveFileName(this, tr("Save Vector Image"), "", tr("Images (*.svg)")); if(filename.isEmpty()) return; if(!filename.endsWith(".svg")) filename += ".svg"; DrawSVG svg(canvas, &mutex); svg.classifier = classifier; svg.regressor = regressor; svg.clusterer = clusterer; svg.dynamical = dynamical; svg.maximizer = maximizer; svg.projector = projector; if(classifier) svg.drawClass = classifiers[tabUsedForTraining]; if(regressor) svg.drawRegr = regressors[tabUsedForTraining]; if(dynamical) svg.drawDyn = dynamicals[tabUsedForTraining]; if(clusterer) svg.drawClust = clusterers[tabUsedForTraining]; if(projector) svg.drawProj = projectors[tabUsedForTraining]; svg.Write(filename); ui.statusBar->showMessage("Vector Image saved successfully"); } void MLDemos::Screenshot() { QString filename = QFileDialog::getSaveFileName(this, tr("Save Screenshot"), "", tr("Images (*.png *.jpg)")); if(filename.isEmpty()) return; if(!filename.endsWith(".jpg") && !filename.endsWith(".png")) filename += ".png"; if(!canvas->SaveScreenshot(filename)) ui.statusBar->showMessage("WARNING: Unable to save image"); else ui.statusBar->showMessage("Image saved successfully"); } void MLDemos::CompareScreenshot() { if(!canvas || !compare) return; QClipboard *clipboard = QApplication::clipboard(); QPixmap screenshot = compare->Display().copy(); clipboard->setImage(screenshot.toImage()); //clipboard->setPixmap(screenshot); clipboard->setText(compare->ToString()); } void MLDemos::ToClipboard() { QPixmap screenshot = canvas->GetScreenshot(); if(screenshot.isNull()) { ui.statusBar->showMessage("WARNING: Nothing to copy to clipboard"); return; } QClipboard *clipboard = QApplication::clipboard(); clipboard->setImage(screenshot.toImage()); clipboard->setPixmap(screenshot); ui.statusBar->showMessage("Image copied successfully to clipboard"); } /************************************/ /* */ /* Input Output functions */ /* */ /************************************/ void MLDemos::ActivateIO() { QList pluginActions = ui.menuInput_Output->actions(); FOR(i, inputoutputs.size()) { if(iisChecked()) { bInputRunning[i] = true; inputoutputs[i]->Start(); } else if(bInputRunning[i]) { bInputRunning[i] = false; inputoutputs[i]->Stop(); } } } } void MLDemos::ActivateImport() { QList pluginActions = ui.menuInput_Output->actions(); FOR(i, inputoutputs.size()) { if(iisChecked()) { bInputRunning[i] = true; inputoutputs[i]->Start(); } else if(bInputRunning[i]) { bInputRunning[i] = false; inputoutputs[i]->Stop(); } } } } void MLDemos::DisactivateIO(QObject *io) { if(!io) return; // first we find the right plugin int pluginIndex = -1; FOR(i, inputoutputs.size()) { if(inputoutputs[i]->object() == io) { pluginIndex = i; break; } } if(pluginIndex == -1) { statusBar()->showMessage("Unable to unload plugin: "); return; // something weird is going on! } QList pluginActions = ui.menuInput_Output->actions(); if(pluginIndex < pluginActions.size() && pluginActions[pluginIndex]) { pluginActions[pluginIndex]->setChecked(false); if(bInputRunning[pluginIndex]) inputoutputs[pluginIndex]->Stop(); bInputRunning[pluginIndex] = false; } pluginActions = ui.menuImport->actions(); if(pluginIndex < pluginActions.size() && pluginActions[pluginIndex]) { pluginActions[pluginIndex]->setChecked(false); if(bInputRunning[pluginIndex]) inputoutputs[pluginIndex]->Stop(); bInputRunning[pluginIndex] = false; } } void MLDemos::SetData(std::vector samples, ivec labels, std::vector trajectories, bool bProjected) { sourceData.clear(); sourceLabels.clear(); projectedData.clear(); if(!canvas) return; canvas->dimNames.clear(); canvas->sampleColors.clear(); canvas->data->Clear(); canvas->data->AddSamples(samples, labels); canvas->data->bProjected = bProjected; if(bProjected) ui.status->setText("Projected Data (PCA, etc.)"); else ui.status->setText("Raw Data"); if(trajectories.size()) { canvas->data->AddSequences(trajectories); } FitToData(); ResetPositiveClass(); ManualSelectionUpdated(); CanvasOptionsChanged(); canvas->ResetSamples(); canvas->repaint(); } void MLDemos::SetDimensionNames(QStringList headers) { qDebug() << "setting dimension names" << headers; canvas->dimNames = headers; ResetPositiveClass(); CanvasOptionsChanged(); canvas->ResetSamples(); canvas->repaint(); } void MLDemos::SetTimeseries(std::vector timeseries) { // qDebug() << "importing " << timeseries.size() << " timeseries"; sourceData.clear(); sourceLabels.clear(); projectedData.clear(); if(!canvas) return; canvas->dimNames.clear(); canvas->sampleColors.clear(); canvas->data->Clear(); canvas->data->AddTimeSeries(timeseries); FitToData(); ResetPositiveClass(); ManualSelectionUpdated(); canvas->ResetSamples(); canvas->repaint(); qDebug() << "added " << canvas->data->GetTimeSeries().size() << " timeseries"; // qDebug() << " dim: " << dim << " count: " << count << " frames: " << frames; /* vector series = canvas->data->GetTimeSeries(); FOR(i, series.size()) { FOR(j, series[i].size()) { qDebug() << i << " " << j << ": " << series[i][j][0]; FOR(d, series[i][j].size()) { // qDebug() << i << " " << j << " " << d << ": " << series[i][j][d]; } } } */ } void MLDemos::QueryClassifier(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); fvec result; result.resize(1); if(classifier && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { result[0] = classifier->Test(samples[i]); results[i] = result; } } emit SendResults(results); } void MLDemos::QueryRegressor(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); if(regressor && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { results[i] = regressor->Test(samples[i]); } } emit SendResults(results); } void MLDemos::QueryDynamical(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); if(dynamical && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { results[i] = dynamical->Test(samples[i]); } } emit SendResults(results); } void MLDemos::QueryClusterer(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); if(clusterer && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { results[i] = clusterer->Test(samples[i]); } } emit SendResults(results); } void MLDemos::QueryMaximizer(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); if(maximizer && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { results[i] = maximizer->Test(samples[i]); } } emit SendResults(results); } void MLDemos::QueryProjector(std::vector samples) { std::vector results; QMutexLocker lock(&mutex); if(projector && samples.size()) { results.resize(samples.size()); FOR(i, samples.size()) { results[i] = projector->Project(samples[i]); } } emit SendResults(results); } mldemos-0.4.3/MLDemos/mldemos.h000066400000000000000000000222461172143270300162750ustar00rootroot00000000000000#ifndef MLDEMOS_H #define MLDEMOS_H /********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 3 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include #include #include #include #include #include "ui_mldemos.h" #include "ui_viewOptions.h" #include "ui_aboutDialog.h" #include "ui_algorithmOptions.h" #include "ui_optsClassify.h" #include "ui_optsCluster.h" #include "ui_optsRegress.h" #include "ui_optsMaximize.h" #include "ui_optsDynamic.h" #include "ui_optsProject.h" #include "ui_optsCompare.h" #include "ui_statisticsDialog.h" #include "ui_drawingTools.h" #include "ui_drawingToolsContext1.h" #include "ui_drawingToolsContext2.h" #include "ui_drawingToolsContext3.h" #include "ui_drawingToolsContext4.h" #include "ui_manualSelection.h" #include "ui_inputDimensions.h" #include "canvas.h" #include "classifier.h" #include "regressor.h" #include "dynamical.h" #include "clusterer.h" #include "interfaces.h" #include "compare.h" #include "widget.h" #include "drawTimer.h" #include "expose.h" #include "dataImporter.h" class MLDemos : public QMainWindow { Q_OBJECT private: QAction *actionAlgorithms, *actionDrawSamples, *actionCompare, *actionDisplayOptions, *actionShowStats, *actionClearData, *actionClearModel, *actionScreenshot, *actionNew, *actionSave, *actionLoad; QDialog *displayDialog, *about, *statsDialog, *manualSelectDialog, *inputDimensionsDialog; QWidget *algorithmWidget, *regressWidget, *dynamicWidget, *classifyWidget, *clusterWidget, *maximizeWidget, *compareWidget, *projectWidget; QNamedWindow *rocWidget, *crossvalidWidget, *infoWidget; Ui::MLDemosClass ui; Ui::viewOptionDialog *displayOptions; Ui::aboutDialog *aboutPanel; Ui::statisticsDialog *showStats; Ui::algorithmOptions *algorithmOptions; Ui::optionsClassifyWidget *optionsClassify; Ui::optionsClusterWidget *optionsCluster; Ui::optionsRegressWidget *optionsRegress; Ui::optionsMaximizeWidget *optionsMaximize; Ui::optionsDynamicWidget *optionsDynamic; Ui::optionsProjectWidget *optionsProject; Ui::optionsCompare *optionsCompare; Ui::DrawingToolbar *drawToolbar; Ui::DrawingToolbarContext1 *drawToolbarContext1; Ui::DrawingToolbarContext2 *drawToolbarContext2; Ui::DrawingToolbarContext3 *drawToolbarContext3; Ui::DrawingToolbarContext4 *drawToolbarContext4; Ui::ManualSelection* manualSelection; Ui::InputDimensions* inputDimensions; QWidget *drawToolbarWidget; QWidget *drawContext1Widget, *drawContext2Widget, *drawContext3Widget, *drawContext4Widget; QToolBar *toolBar; DrawTimer *drawTimer; QTime drawTime; Canvas *canvas; Expose *expose; DataImporter *import; ipair trajectory; Obstacle obstacle; bool bNewObstacle; QString lastTrainingInfo; void closeEvent(QCloseEvent *event); bool Train(Classifier *classifier, int positive, float trainRatio=1, bvec trainList = bvec()); void Train(Regressor *regressor, int outputDim=-1, float trainRatio=1, bvec trainList = bvec()); fvec Train(Dynamical *dynamical); void Train(Clusterer *clusterer, bvec trainList = bvec()); void Train(Maximizer *maximizer); void Train(Projector *projector, bvec trainList = bvec()); fvec Test(Dynamical *dynamical, std::vector< std::vector > trajectories, ivec labels); void Test(Maximizer *maximizer); QList classifiers; QList clusterers; QList regressors; QList dynamicals; QList avoiders; QList maximizers; QList projectors; QList inputoutputs; QList bInputRunning; QList compareOptions; QLabel *compareDisplay; CompareAlgorithms *compare; void AddPlugin(ClassifierInterface *iClassifier, const char *method); void AddPlugin(ClustererInterface *iCluster, const char *method); void AddPlugin(RegressorInterface *iRegress, const char *method); void AddPlugin(DynamicalInterface *iDynamical, const char *method); void AddPlugin(AvoidanceInterface *iAvoid, const char *method); void AddPlugin(MaximizeInterface *iMaximize, const char *method); void AddPlugin(ProjectorInterface *iProject, const char *method); void AddPlugin(InputOutputInterface *iIO); void initDialogs(); void initToolBars(); void initPlugins(); void SaveLayoutOptions(); void LoadLayoutOptions(); void SetTextFontSize(); void SaveParams(QString filename); void LoadParams(QString filename); void Load(QString filename); void Save(QString filename); void ImportData(QString filename); std::vector GetManualSelection(); ivec GetInputDimensions(); void UpdateInfo(); void SetCrossValidationInfo(); bool bIsRocNew; bool bIsCrossNew; public: MLDemos(QString filename="", QWidget *parent = 0, Qt::WFlags flags = 0); ~MLDemos(); int tabUsedForTraining; Classifier *classifier; Regressor *regressor; Dynamical *dynamical; Clusterer *clusterer; Maximizer *maximizer; Projector *projector; std::vector sourceData; std::vector projectedData; ivec sourceLabels; QMutex mutex; void resizeEvent( QResizeEvent *event ); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); signals: void SendResults(std::vector results); public slots: void SetData(std::vector samples, ivec labels, std::vector trajectories, bool bProjected); void SetTimeseries(std::vector timeseries); void SetDimensionNames(QStringList headers); void QueryClassifier(std::vector samples); void QueryRegressor(std::vector samples); void QueryDynamical(std::vector samples); void QueryClusterer(std::vector samples); void QueryMaximizer(std::vector samples); void QueryProjector(std::vector samples); private slots: void ShowAbout(); void ShowAlgorithmOptions(); void ShowOptionCompare(); void ShowSampleDrawing(); void ShowOptionDisplay(); void ShowStatsDialog(); void ShowToolbar(); void HideSampleDrawing(); void HideOptionDisplay(); void HideStatsDialog(); void HideToolbar(); void AvoidOptionChanged(); void DisplayOptionChanged(); void ColorMapChanged(); void ActivateIO(); void ActivateImport(); void DisactivateIO(QObject *); void Classify(); void ClassifyCross(); void Regression(); void RegressionCross(); void Maximize(); void MaximizeContinue(); void Dynamize(); void Cluster(); void ClusterIterate(); void ClusterOptimize(); void Project(); void ProjectRevert(); void ProjectReproject(); void Avoidance(); void Compare(); void CompareScreenshot(); void Clear(); void ClearData(); void SetROCInfo(); void SaveData(); void LoadData(); void ImportData(); void ExportOutput(); void ExportAnimation(); void ExportSVG(); void Screenshot(); void ToClipboard(); void DrawCrosshair(); void DrawSingle(); void DrawSpray(); void DrawLine(); void DrawTrajectory(); void DrawEllipse(); void DrawErase(); void DrawObstacle(); void DrawPaint(); void Drawing(fvec sample, int label); void DrawingStopped(); void ManualSelection(); void InputDimensions(); void ExposeData(); void FitToData(); void ZoomChanged(float d); void UpdateLearnedModel(); void CanvasMoveEvent(); void Navigation(fvec sample); void ResetPositiveClass(); void ChangeActiveOptions(); void ShowRoc(); void ShowCross(); void MouseOnRoc(QMouseEvent *event); void StatsChanged(); void AlgoChanged(); void ChangeInfoFile(); void ManualSelectionUpdated(); void ManualSelectionChanged(); void ManualSelectionClear(); void ManualSelectionInvert(); void ManualSelectionRemove(); void ManualSelectionRandom(); void InputDimensionsUpdated(); void InputDimensionsChanged(); void InputDimensionsClear(); void InputDimensionsInvert(); void InputDimensionsRandom(); void TargetButton(); void GaussianButton(); void GradientButton(); void BenchmarkButton(); void CompareAdd(); void CompareClear(); void CompareRemove(); void CanvasTypeChanged(); void CanvasOptionsChanged(); void ShowContextMenuSpray(const QPoint &point); void ShowContextMenuLine(const QPoint &point); void ShowContextMenuEllipse(const QPoint &point); void ShowContextMenuErase(const QPoint &point); void ShowContextMenuObstacle(const QPoint &point); void ShowContextMenuReward(const QPoint &point); void FocusChanged(QWidget *old, QWidget *now); void HideContextMenus(); }; #endif // MLDEMOS_H mldemos-0.4.3/MLDemos/mldemos.qrc000066400000000000000000000016131172143270300166260ustar00rootroot00000000000000 icons/project.png icons/save.png icons/screenshot.png icons/cleardata.png icons/clearmodel.png icons/display.png icons/draw.png icons/load.png icons/new.png logo.png icons/stats.png icons/airbrush.png icons/brush.png icons/erase.png icons/eraser.png icons/obstacle.png icons/trajectory.png icons/bigbrush.png icons/ellipse.png icons/line.png icons/compare.png icons/algorithms.png mldemos-0.4.3/MLDemos/mldemos.ui000066400000000000000000000344151172143270300164640ustar00rootroot00000000000000 MLDemosClass 0 0 636 475 0 0 MLDemos Qt::ToolButtonIconOnly false 0 0 0 0 0 0 true 0 0 634 399 0 0 0 0 Standard Scatterplots Parallel Coordinates Radial Graph Andrews Plots Bubble Plots false 0 100 Qt::Horizontal false QSlider::TicksAbove 5 -1 0 0 10 1 10 1 2 10 0 0 10 x Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 10 y Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 10 size Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 0 0 25 0 0 636 22 File Export Import Edit Toolbar Options true Plugins Input / Output Help New Exit Clear Data Save Load Close true Classification true Regression true Clustering true Draw Samples true Projections Undo Redo true Display Options Clear Model About false Output Data Export algorithm output for current samples false Parameter Animation Export image sequence animating selected parameters false Manage Plugins none true true Show Toolbar true true Small Icons Vector Image (SVG) Comma Separated Values Data (csv, txt) mldemos-0.4.3/MLDemos/mlprocessing.cpp000066400000000000000000001146761172143270300177060ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include "basicMath.h" #include "classifier.h" #include "regressor.h" #include "dynamical.h" #include "clusterer.h" #include "maximize.h" #include "roc.h" #include #include #include #include #include #include #include using namespace std; void MLDemos::Classify() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); drawTimer->Clear(); mutex.lock(); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsClassify->tabWidget->currentIndex(); if(tab >= classifiers.size() || !classifiers[tab]) return; classifier = classifiers[tab]->GetClassifier(); tabUsedForTraining = tab; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = optionsClassify->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; int positive = optionsClassify->positiveSpin->value(); vector trainList; if(optionsClassify->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } bool trained = Train(classifier, positive, trainRatio, trainList); if(trained) { classifiers[tab]->Draw(canvas, classifier); UpdateInfo(); if(drawTimer && classifier->UsesDrawTimer()) { drawTimer->classifier = &this->classifier; drawTimer->start(QThread::NormalPriority); } if(canvas->canvasType) CanvasOptionsChanged(); // we fill in the canvas sampleColors vector samples = canvas->data->GetSamples(); canvas->sampleColors.resize(samples.size()); FOR(i, samples.size()) { canvas->sampleColors[i] = DrawTimer::GetColor(classifier, samples[i]); } if(canvas->canvasType) { canvas->maps.model = QPixmap(); CanvasOptionsChanged(); } canvas->repaint(); } else { mutex.unlock(); Clear(); mutex.lock(); UpdateInfo(); } mutex.unlock(); } void MLDemos::ClassifyCross() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsClassify->tabWidget->currentIndex(); if(tab >= classifiers.size() || !classifiers[tab]) return; tabUsedForTraining = tab; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = optionsClassify->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; int positive = optionsClassify->positiveSpin->value(); int foldCount = optionsClassify->foldCountSpin->value(); vector trainList; if(optionsClassify->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } vector fmeasures; fmeasures.resize(2); bool trained = false; FOR(f,foldCount) { DEL(classifier); classifier = classifiers[tab]->GetClassifier(); trained = Train(classifier, positive, trainRatio, trainList); if(!trained) break; if(classifier->rocdata.size()>0) { fmeasures[0].push_back(GetBestFMeasure(classifier->rocdata[0])[0]); } if(classifier->rocdata.size()>1) { fmeasures[1].push_back(GetBestFMeasure(classifier->rocdata[1])[0]); } } classifier->crossval = fmeasures; ShowCross(); //if(trained) classifiers[tab]->Draw(canvas, classifier); DEL(classifier); UpdateInfo(); } vector MLDemos::GetManualSelection() { vector trainList; if(!canvas || !canvas->data->GetCount()) return trainList; trainList.resize(manualSelection->sampleList->count(), false); QList selected = manualSelection->sampleList->selectedItems(); if(!selected.size()) // if nothing is selected we use all samples as training { trainList = vector(canvas->data->GetCount(), true); return trainList; } FOR(i, selected.size()) { int index = manualSelection->sampleList->row(selected[i]); trainList[index] = true; } return trainList; } ivec MLDemos::GetInputDimensions() { if(!canvas || !canvas->data->GetCount()) return ivec(); QList selected = inputDimensions->dimList->selectedItems(); if(!selected.size() || selected.size() == inputDimensions->dimList->count()) return ivec(); // if nothing is selected we use all dimensions for training ivec dimList(selected.size()); FOR(i, selected.size()) { dimList[i] = inputDimensions->dimList->row(selected[i]); } return dimList; } void MLDemos::Regression() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsRegress->tabWidget->currentIndex(); if(tab >= regressors.size() || !regressors[tab]) return; int outputDim = optionsRegress->outputDimCombo->currentIndex(); ivec inputDims = GetInputDimensions(); //ivec inputDims = optionsRegress->inputDimButton->isChecked() ? GetInputDimensions() : ivec(); if(inputDims.size()==1 && inputDims[0] == outputDim) return; int outputIndexInList = -1; FOR(i, inputDims.size()) if(outputDim == inputDims[i]) { outputIndexInList = i; break; } regressor = regressors[tab]->GetRegressor(); tabUsedForTraining = tab; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = optionsRegress->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; vector trainList; if(optionsRegress->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } Train(regressor, outputDim, trainRatio, trainList); if(outputDim != -1) { ui.canvasX2Spin->setValue(outputDim+1); DisplayOptionChanged(); } regressors[tab]->Draw(canvas, regressor); // here we draw the errors for each sample if(canvas->data->GetDimCount() > 2 && canvas->canvasType == 0) { vector samples = canvas->data->GetSamples(); vector subsamples = canvas->data->GetSampleDims(inputDims, outputIndexInList==-1 ? outputDim : -1); ivec labels = canvas->data->GetLabels(); QPainter painter(&canvas->maps.model); painter.setRenderHint(QPainter::Antialiasing); // we draw the starting sample painter.setOpacity(0.4); painter.setPen(Qt::black); painter.setBrush(Qt::white); FOR(i, samples.size()) { fvec sample = samples[i]; QPointF point = canvas->toCanvasCoords(sample); painter.drawEllipse(point, 6,6); } // we draw the estimated sample painter.setPen(Qt::white); painter.setBrush(Qt::black); FOR(i, samples.size()) { fvec sample = samples[i]; fvec estimate = regressor->Test(subsamples[i]); sample[outputDim] = estimate[0]; QPointF point2 = canvas->toCanvasCoords(sample); painter.drawEllipse(point2, 5,5); } painter.setOpacity(1); // we draw the error bars FOR(i, samples.size()) { fvec sample = samples[i]; fvec estimate = regressor->Test(subsamples[i]); QPointF point = canvas->toCanvasCoords(sample); sample[outputDim] = estimate[0]; QPointF point2 = canvas->toCanvasCoords(sample); QColor color = SampleColor[labels[i]%SampleColorCnt]; if(!labels[i]) color = Qt::black; painter.setPen(QPen(color, 1)); painter.drawLine(point, point2); } } UpdateInfo(); } void MLDemos::RegressionCross() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsRegress->tabWidget->currentIndex(); if(tab >= regressors.size() || !regressors[tab]) return; int outputDim = optionsRegress->outputDimCombo->currentIndex(); regressor = regressors[tab]->GetRegressor(); tabUsedForTraining = tab; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = optionsRegress->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; int foldCount = optionsRegress->foldCountSpin->value(); vector errors; errors.resize(2); FOR(f,foldCount) { DEL(regressor); regressor = regressors[tab]->GetRegressor(); Train(regressor, trainRatio); if(regressor->trainErrors.size()) { errors[0] = regressor->trainErrors; } if(regressor->testErrors.size()) { errors[1] = regressor->testErrors; } } regressor->crossval = errors; ShowCross(); Train(regressor, outputDim, trainRatio); regressors[tab]->Draw(canvas, regressor); UpdateInfo(); } void MLDemos::Dynamize() { if(!canvas || !canvas->data->GetCount() || !canvas->data->GetSequences().size()) return; drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsDynamic->tabWidget->currentIndex(); if(tab >= dynamicals.size() || !dynamicals[tab]) return; dynamical = dynamicals[tab]->GetDynamical(); tabUsedForTraining = tab; Train(dynamical); dynamicals[tab]->Draw(canvas,dynamical); int w = canvas->width(), h = canvas->height(); int resampleType = optionsDynamic->resampleCombo->currentIndex(); int resampleCount = optionsDynamic->resampleSpin->value(); int centerType = optionsDynamic->centerCombo->currentIndex(); float dT = optionsDynamic->dtSpin->value(); int zeroEnding = optionsDynamic->zeroCheck->isChecked(); bool bColorMap = optionsDynamic->colorCheck->isChecked(); // we draw the current trajectories vector< vector > trajectories = canvas->data->GetTrajectories(resampleType, resampleCount, centerType, dT, zeroEnding); vector< vector > testTrajectories; int steps = 300; if(trajectories.size()) { testTrajectories.resize(trajectories.size()); int dim = trajectories[0][0].size() / 2; FOR(i, trajectories.size()) { fvec start(dim,0); FOR(d, dim) start[d] = trajectories[i][0][d]; vector result = dynamical->Test(start, steps); testTrajectories[i] = result; } canvas->maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.model.setMask(bitmap); canvas->maps.model.fill(Qt::transparent); if(canvas->canvasType == 0) // standard canvas { QPainter painter(&canvas->maps.model); painter.setRenderHint(QPainter::Antialiasing); FOR(i, testTrajectories.size()) { vector &result = testTrajectories[i]; fvec oldPt = result[0]; int count = result.size(); FOR(j, count-1) { fvec pt = result[j+1]; painter.setPen(QPen(Qt::green, 2)); painter.drawLine(canvas->toCanvasCoords(pt), canvas->toCanvasCoords(oldPt)); oldPt = pt; } painter.setBrush(Qt::NoBrush); painter.setPen(Qt::green); painter.drawEllipse(canvas->toCanvasCoords(result[0]), 5, 5); painter.setPen(Qt::red); painter.drawEllipse(canvas->toCanvasCoords(result[count-1]), 5, 5); } } else { pair bounds = canvas->data->GetBounds(); Expose::DrawTrajectories(canvas->maps.model, testTrajectories, vector(), canvas->canvasType-1, 1, bounds); } } // the first index is "none", so we subtract 1 int avoidIndex = optionsDynamic->obstacleCombo->currentIndex()-1; if(avoidIndex >=0 && avoidIndex < avoiders.size() && avoiders[avoidIndex]) { DEL(dynamical->avoid); dynamical->avoid = avoiders[avoidIndex]->GetObstacleAvoidance(); } UpdateInfo(); if(dynamicals[tab]->UsesDrawTimer()) { drawTimer->bColorMap = bColorMap; drawTimer->start(QThread::NormalPriority); } } void MLDemos::Avoidance() { if(!canvas || !dynamical) return; drawTimer->Stop(); QMutexLocker lock(&mutex); // the first index is "none", so we subtract 1 int index = optionsDynamic->obstacleCombo->currentIndex()-1; if(index >=0 && index >= avoiders.size() || !avoiders[index]) return; DEL(dynamical->avoid); dynamical->avoid = avoiders[index]->GetObstacleAvoidance(); UpdateInfo(); drawTimer->Clear(); drawTimer->start(QThread::NormalPriority); } fvec ClusterMetrics(std::vector samples, ivec labels, std::vector scores, float ratio = 1.f) { fvec results(4, 0); results[0] = drand48(); if(!samples.size() || !scores.size()) return results; int dim = samples[0].size(); int nbClusters = scores[0].size(); int count = samples.size(); // compute bic double loglik = 0; vector means(nbClusters); FOR(k, nbClusters) { means[k] = fvec(dim, 0); float contrib = 0; FOR(i, count) { contrib += scores[i][k]; means[k] += samples[i]*scores[i][k]; } means[k] /= contrib; } float log_lik=0; float like; float *pxi = new float[nbClusters]; int data_i=0; int state_i; fvec loglikes(nbClusters); FOR(k, nbClusters) { float rss = 0; double contrib = 0; FOR(i, count) { contrib += scores[i][k]; if(contrib==0) continue; fvec diff = samples[i]-means[k]; rss += diff*diff*scores[i][k]; } loglikes[k] = rss; } FOR(k, nbClusters) loglik += loglikes[k]; //loglik /= nbClusters; results[0] = loglik; // RSS results[1] = log(count)*nbClusters + loglik; // BIC results[2] = 2*nbClusters + loglik; // AIC // we compute the f-measures for each class map classcounts; int cnt = 0; FOR(i, labels.size()) if(!classcounts.count(labels[i])) classcounts[labels[i]] = cnt++; int classCount = classcounts.size(); map classScores; fvec clusterScores(nbClusters); map labelScores; if(ratio == 1.f) { FOR(i, labels.size()) { labelScores[labels[i]] += 1.f; if(!classScores.count(labels[i]))classScores[labels[i]].resize(nbClusters); FOR(k, nbClusters) { classScores[labels[i]][k] += scores[i][k]; clusterScores[k] += scores[i][k]; } } } else { u32 *perm = randPerm(labels.size()); map indices; FOR(i, labels.size()) indices[labels[perm[i]]].push_back(perm[i]); for(map::iterator it = indices.begin(); it != indices.end(); it++) { int labelCount = max(1,int(it->second.size()*ratio)); FOR(i, labelCount) { labelScores[labels[it->second[i]]] += 1.f; if(!classScores.count(labels[it->second[i]]))classScores[labels[it->second[i]]].resize(nbClusters); FOR(k, nbClusters) { classScores[labels[it->second[i]]][k] += scores[it->second[i]][k]; clusterScores[k] += scores[it->second[i]][k]; } } } delete [] perm; } float fmeasure = 0; map::iterator it2 = labelScores.begin(); for(map::iterator it = classScores.begin(); it != classScores.end(); it++, it2++) { float maxScore = -FLT_MAX; FOR(k, nbClusters) { float precision = it->second[k] / it2->second; float recall = it->second[k] / clusterScores[k]; float f1 = 2*precision*recall/(precision+recall); maxScore = max(maxScore,f1); } fmeasure += maxScore; } int classAndClusterCount = classCount; // we penalize empty clusters FOR(k, nbClusters) if(clusterScores[k] == 0) classAndClusterCount++; // we have an empty cluster! fmeasure /= classAndClusterCount; results[3] = -fmeasure; // F-Measure return results; } void MLDemos::Cluster() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsCluster->tabWidget->currentIndex(); if(tab >= clusterers.size() || !clusterers[tab]) return; clusterer = clusterers[tab]->GetClusterer(); tabUsedForTraining = tab; vector trainList; if(optionsCluster->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } Train(clusterer, trainList); drawTimer->Stop(); drawTimer->Clear(); clusterers[tab]->Draw(canvas,clusterer); // we compute the stats on the clusters (f-measure, bic etc) vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); vector clusterScores(samples.size()); FOR(i, canvas->data->GetCount()) { fvec result = clusterer->Test(samples[i]); if(clusterer->NbClusters()==1) clusterScores[i] = result; else if(result.size()>1) clusterScores[i] = result; else if(result.size()) { fvec res(clusterer->NbClusters(),0); res[result[0]] = 1.f; } } int ratioIndex = optionsCluster->trainRatioCombo->currentIndex(); float ratios[] = {0.01f, 0.05f, 0.1f, 0.2f, 1.f/3.f, 0.5f, 0.75f, 1.f}; float ratio = ratios[ratioIndex]; fvec clusterMetrics = ClusterMetrics(samples, labels, clusterScores, ratio); optionsCluster->resultList->clear(); optionsCluster->resultList->addItem(QString("rss: %1").arg(clusterMetrics[0], 0, 'f', 2)); optionsCluster->resultList->addItem(QString("bic: %1").arg(clusterMetrics[1], 0, 'f', 2)); optionsCluster->resultList->addItem(QString("aic: %1").arg(clusterMetrics[2], 0, 'f', 2)); optionsCluster->resultList->addItem(QString("f1: %1").arg(clusterMetrics[3], 0, 'f', 2)); FOR(i, clusterMetrics.size()) { optionsCluster->resultList->item(i)->setForeground(i ? SampleColor[i%SampleColorCnt] : Qt::gray); } // we fill in the canvas sampleColors for the alternative display types canvas->sampleColors.resize(samples.size()); FOR(i, samples.size()) { fvec res = clusterer->Test(samples[i]); float r=0,g=0,b=0; if(res.size() > 1) { FOR(j, res.size()) { r += SampleColor[(j+1)%SampleColorCnt].red()*res[j]; g += SampleColor[(j+1)%SampleColorCnt].green()*res[j]; b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j]; } } else if(res.size()) { r = (1-res[0])*255 + res[0]* 255; g = (1-res[0])*255; b = (1-res[0])*255; } canvas->sampleColors[i] = QColor(r,g,b); } canvas->maps.model = QPixmap(); canvas->repaint(); UpdateInfo(); drawTimer->clusterer= &this->clusterer; drawTimer->start(QThread::NormalPriority); } void MLDemos::ClusterOptimize() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); drawTimer->Clear(); QMutexLocker lock(&mutex); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsCluster->tabWidget->currentIndex(); if(tab >= clusterers.size() || !clusterers[tab]) return; clusterer = clusterers[tab]->GetClusterer(); tabUsedForTraining = tab; int startCount=1, stopCount=11; vector samples = canvas->data->GetSamples(); ivec labels = canvas->data->GetLabels(); int ratioIndex = optionsCluster->trainRatioCombo->currentIndex(); float ratios[] = {0.01f, 0.05f, 0.1f, 0.2f, 1.f/3.f, 0.5f, 0.75f, 1.f}; float ratio = ratios[ratioIndex]; vector trainList; if(optionsCluster->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } ivec kCounts; vector results(4); for(int k=startCount; kSetNbClusters(k); Train(clusterer, trainList); int folds = 10; fvec metricMeans(results.size()); ivec foldCount(results.size()); FOR(f, folds) { vector clusterScores(samples.size()); FOR(i, canvas->data->GetCount()) { fvec result = clusterer->Test(samples[i]); if(clusterer->NbClusters()==1) clusterScores[i] = result; else if(result.size()>1) clusterScores[i] = result; else if(result.size()) { fvec res(clusterer->NbClusters(),0); res[result[0]] = 1.f; } } fvec clusterMetrics = ClusterMetrics(samples, labels, clusterScores, ratio); FOR(d, clusterMetrics.size()) { if(clusterMetrics[d] != clusterMetrics[d]) continue; metricMeans[d] += clusterMetrics[d]; foldCount[d]++; } } FOR(d, metricMeans.size()) metricMeans[d] /= foldCount[d]; kCounts.push_back(k); FOR(i, metricMeans.size()) results[i].push_back(metricMeans[i]); } int w = optionsCluster->graphLabel->width(); int h = optionsCluster->graphLabel->height(); int pad = 6; QPixmap pixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); pixmap.setMask(bitmap); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setPen(QPen(Qt::black, 1.f)); painter.drawLine(pad, h - 2*pad, w-pad, h-2*pad); painter.drawLine(pad, 0, pad, h-2*pad); QFont font = painter.font(); font.setPointSize(9); painter.setFont(font); FOR(k, kCounts.size()) { float x = k/(float)(kCounts.size()-1); painter.drawLine(x*(w-2*pad)+pad, h-2*pad-1, x*(w-2*pad)+pad, h-2*pad+1); if(k == kCounts.size()-1) x -= 0.05; painter.drawText(x*(w-2*pad)-2+pad, h-1, QString("%1").arg(kCounts[k])); } painter.setRenderHint(QPainter::Antialiasing); fvec mins(results.size(), FLT_MAX), maxes(results.size(), -FLT_MAX); FOR(i, results.size()) { FOR(j, results[i].size()) { mins[i] = min(mins[i], results[i][j]); maxes[i] = max(maxes[i], results[i][j]); } } vector< pair > bests(results.size()); FOR(i, results.size()) { QPointF old; painter.setPen(QPen(i ? SampleColor[i%SampleColorCnt] : Qt::gray,2)); bests[i] = make_pair(FLT_MAX, 0); FOR(k, kCounts.size()) { if(results[i][k] < bests[i].first) { bests[i] = make_pair(results[i][k], kCounts[k]); } float x = k/(float)(kCounts.size()-1); float y = (results[i][k] - mins[i])/(maxes[i]-mins[i]); if(i == 3) y = 1.f - y; // fmeasures needs to be maximized QPointF point(x*(w-2*pad)+pad, (1.f-y)*(h-2*pad)); if(k) painter.drawLine(old, point); old = point; } } optionsCluster->graphLabel->setPixmap(pixmap); optionsCluster->resultList->clear(); optionsCluster->resultList->addItem(QString("rss: %1 (%2)").arg(bests[0].second).arg(bests[0].first, 0, 'f', 2)); optionsCluster->resultList->addItem(QString("bic: %1 (%2)").arg(bests[1].second).arg(bests[1].first, 0, 'f', 2)); optionsCluster->resultList->addItem(QString("aic: %1 (%2)").arg(bests[2].second).arg(bests[2].first, 0, 'f', 2)); optionsCluster->resultList->addItem(QString("f1: %1 (%2)").arg(bests[3].second).arg(-bests[3].first, 0, 'f', 2)); FOR(i, results.size()) { optionsCluster->resultList->item(i)->setForeground(i ? SampleColor[i%SampleColorCnt] : Qt::gray); } int bestIndex = optionsCluster->optimizeCombo->currentIndex(); clusterer->SetNbClusters(bests[bestIndex].second); Train(clusterer); // we fill in the canvas sampleColors for the alternative display types canvas->sampleColors.resize(samples.size()); FOR(i, samples.size()) { fvec res = clusterer->Test(samples[i]); float r=0,g=0,b=0; if(res.size() > 1) { FOR(j, res.size()) { r += SampleColor[(j+1)%SampleColorCnt].red()*res[j]; g += SampleColor[(j+1)%SampleColorCnt].green()*res[j]; b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j]; } } else if(res.size()) { r = (1-res[0])*255 + res[0]* 255; g = (1-res[0])*255; b = (1-res[0])*255; } canvas->sampleColors[i] = QColor(r,g,b); } canvas->maps.model = QPixmap(); clusterers[tab]->Draw(canvas, clusterer); drawTimer->Clear(); UpdateInfo(); drawTimer->clusterer= &this->clusterer; drawTimer->start(QThread::NormalPriority); canvas->repaint(); } void MLDemos::ClusterIterate() { if(!canvas || !canvas->data->GetCount()) return; drawTimer->Stop(); int tab = optionsCluster->tabWidget->currentIndex(); if(tab >= clusterers.size() || !clusterers[tab]) return; QMutexLocker lock(&mutex); if(!clusterer) { clusterer = clusterers[tab]->GetClusterer(); tabUsedForTraining = tab; } else clusterers[tab]->SetParams(clusterer); clusterer->SetIterative(true); Train(clusterer); clusterers[tab]->Draw(canvas,clusterer); // we fill in the canvas sampleColors vector samples = canvas->data->GetSamples(); canvas->sampleColors.resize(samples.size()); FOR(i, samples.size()) { fvec res = clusterer->Test(samples[i]); float r=0,g=0,b=0; if(res.size() > 1) { FOR(j, res.size()) { r += SampleColor[(j+1)%SampleColorCnt].red()*res[j]; g += SampleColor[(j+1)%SampleColorCnt].green()*res[j]; b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j]; } } else if(res.size()) { r = (1-res[0])*255 + res[0]* 255; g = (1-res[0])*255; b = (1-res[0])*255; } canvas->sampleColors[i] = QColor(r,g,b); } canvas->maps.model = QPixmap(); canvas->repaint(); UpdateInfo(); } void MLDemos::Maximize() { if(!canvas) return; if(canvas->maps.reward.isNull()) return; QMutexLocker lock(&mutex); drawTimer->Stop(); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsMaximize->tabWidget->currentIndex(); if(tab >= maximizers.size() || !maximizers[tab]) return; maximizer = maximizers[tab]->GetMaximizer(); maximizer->maxAge = optionsMaximize->iterationsSpin->value(); maximizer->stopValue = optionsMaximize->stoppingSpin->value(); tabUsedForTraining = tab; Train(maximizer); UpdateInfo(); drawTimer->Stop(); drawTimer->Clear(); drawTimer->start(QThread::NormalPriority); } void MLDemos::MaximizeContinue() { if(!canvas || !maximizer) return; QMutexLocker lock(&mutex); if(drawTimer) { drawTimer->Stop(); } maximizer->SetConverged(!maximizer->hasConverged()); UpdateInfo(); if(drawTimer) { drawTimer->start(QThread::NormalPriority); } } void MLDemos::Project() { if(!canvas) return; QMutexLocker lock(&mutex); drawTimer->Stop(); drawTimer->Clear(); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; int tab = optionsProject->tabWidget->currentIndex(); if(tab >= projectors.size() || !projectors[tab]) return; projector = projectors[tab]->GetProjector(); projectors[tab]->SetParams(projector); tabUsedForTraining = tab; bool bHasSource = false; if(sourceData.size() && sourceData.size() == canvas->data->GetCount()) { bHasSource = true; canvas->data->SetSamples(sourceData); canvas->data->SetLabels(sourceLabels); } vector trainList; if(optionsProject->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } Train(projector, trainList); if(!bHasSource) { sourceData = canvas->data->GetSamples(); sourceLabels = canvas->data->GetLabels(); } projectedData = projector->GetProjected(); if(projectedData.size()) { canvas->data->SetSamples(projectedData); canvas->data->bProjected = true; } //canvas->FitToData(); CanvasTypeChanged(); CanvasOptionsChanged(); if(!canvas->canvasType) { projectors[tab]->Draw(canvas, projector); } canvas->repaint(); UpdateInfo(); } void MLDemos::ProjectRevert() { QMutexLocker lock(&mutex); drawTimer->Stop(); drawTimer->Clear(); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); lastTrainingInfo = ""; if(!sourceData.size()) return; canvas->data->SetSamples(sourceData); canvas->data->SetLabels(sourceLabels); canvas->data->bProjected = false; canvas->maps.info = QPixmap(); canvas->maps.model = QPixmap(); canvas->FitToData(); CanvasTypeChanged(); CanvasOptionsChanged(); canvas->repaint(); UpdateInfo(); sourceData.clear(); sourceLabels.clear(); } void MLDemos::ProjectReproject() { if(!canvas) return; mutex.lock(); sourceData = canvas->data->GetSamples(); sourceLabels = canvas->data->GetLabels(); mutex.unlock(); Project(); } void MLDemos::ExportOutput() { if(!classifier && !regressor && !clusterer && !dynamical && !maximizer) return; // get a file } void MLDemos::ExportAnimation() { if(!canvas->data->GetSamples().size()) return; } void MLDemos::UpdateLearnedModel() { if(!canvas) return; if(!clusterer && !regressor && !dynamical && !classifier && !projector) return; if(classifier) { QMutexLocker lock(&mutex); classifiers[tabUsedForTraining]->Draw(canvas, classifier); if(classifier->UsesDrawTimer() && !drawTimer->isRunning()) { drawTimer->start(QThread::NormalPriority); } } if(clusterer) { QMutexLocker lock(&mutex); clusterers[tabUsedForTraining]->Draw(canvas, clusterer); } if(regressor) { QMutexLocker lock(&mutex); regressors[tabUsedForTraining]->Draw(canvas, regressor); // here we draw the errors for each sample int outputDim = optionsRegress->outputDimCombo->currentIndex(); ivec inputDims = GetInputDimensions(); //ivec inputDims = optionsRegress->inputDimButton->isChecked() ? GetInputDimensions() : ivec(); if(inputDims.size()==1 && inputDims[0] == outputDim) return; int outputIndexInList = -1; FOR(i, inputDims.size()) if(outputDim == inputDims[i]) { outputIndexInList = i; break; } if(canvas->data->GetDimCount() > 2 && canvas->canvasType == 0) { vector samples = canvas->data->GetSamples(); vector subsamples = canvas->data->GetSampleDims(inputDims, outputIndexInList==-1 ? outputDim : -1); ivec labels = canvas->data->GetLabels(); QPainter painter(&canvas->maps.model); painter.setRenderHint(QPainter::Antialiasing); // we draw the starting sample painter.setOpacity(0.4); painter.setPen(Qt::black); painter.setBrush(Qt::white); FOR(i, samples.size()) { fvec sample = samples[i]; QPointF point = canvas->toCanvasCoords(sample); painter.drawEllipse(point, 6,6); } // we draw the estimated sample painter.setPen(Qt::white); painter.setBrush(Qt::black); FOR(i, samples.size()) { fvec sample = samples[i]; fvec estimate = regressor->Test(subsamples[i]); sample[outputDim] = estimate[0]; QPointF point2 = canvas->toCanvasCoords(sample); painter.drawEllipse(point2, 5,5); } painter.setOpacity(1); // we draw the error bars FOR(i, samples.size()) { fvec sample = samples[i]; fvec estimate = regressor->Test(subsamples[i]); QPointF point = canvas->toCanvasCoords(sample); sample[outputDim] = estimate[0]; QPointF point2 = canvas->toCanvasCoords(sample); QColor color = SampleColor[labels[i]%SampleColorCnt]; if(!labels[i]) color = Qt::black; painter.setPen(QPen(color, 1)); painter.drawLine(point, point2); } } } if(dynamical) { QMutexLocker lock(&mutex); dynamicals[tabUsedForTraining]->Draw(canvas, dynamical); int w = canvas->width(), h = canvas->height(); int resampleType = optionsDynamic->resampleCombo->currentIndex(); int resampleCount = optionsDynamic->resampleSpin->value(); int centerType = optionsDynamic->centerCombo->currentIndex(); float dT = optionsDynamic->dtSpin->value(); int zeroEnding = optionsDynamic->zeroCheck->isChecked(); bool bColorMap = optionsDynamic->colorCheck->isChecked(); // we draw the current trajectories vector< vector > trajectories = canvas->data->GetTrajectories(resampleType, resampleCount, centerType, dT, zeroEnding); vector< vector > testTrajectories; int steps = 300; if(trajectories.size()) { testTrajectories.resize(trajectories.size()); int dim = trajectories[0][0].size() / 2; FOR(i, trajectories.size()) { fvec start(dim,0); FOR(d, dim) start[d] = trajectories[i][0][d]; vector result = dynamical->Test(start, steps); testTrajectories[i] = result; } canvas->maps.model = QPixmap(w,h); QBitmap bitmap(w,h); bitmap.clear(); canvas->maps.model.setMask(bitmap); canvas->maps.model.fill(Qt::transparent); if(canvas->canvasType == 0) // standard canvas { QPainter painter(&canvas->maps.model); painter.setRenderHint(QPainter::Antialiasing); FOR(i, testTrajectories.size()) { vector &result = testTrajectories[i]; fvec oldPt = result[0]; int count = result.size(); FOR(j, count-1) { fvec pt = result[j+1]; painter.setPen(QPen(Qt::green, 2)); painter.drawLine(canvas->toCanvasCoords(pt), canvas->toCanvasCoords(oldPt)); oldPt = pt; } painter.setBrush(Qt::NoBrush); painter.setPen(Qt::green); painter.drawEllipse(canvas->toCanvasCoords(result[0]), 5, 5); painter.setPen(Qt::red); painter.drawEllipse(canvas->toCanvasCoords(result[count-1]), 5, 5); } } else { pair bounds = canvas->data->GetBounds(); Expose::DrawTrajectories(canvas->maps.model, testTrajectories, vector(), canvas->canvasType-1, 1, bounds); } } // the first index is "none", so we subtract 1 int avoidIndex = optionsDynamic->obstacleCombo->currentIndex()-1; if(avoidIndex >=0 && avoidIndex < avoiders.size() && avoiders[avoidIndex]) { DEL(dynamical->avoid); dynamical->avoid = avoiders[avoidIndex]->GetObstacleAvoidance(); } UpdateInfo(); if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) { drawTimer->bColorMap = bColorMap; drawTimer->start(QThread::NormalPriority); } } if(projector) { projectors[tabUsedForTraining]->Draw(canvas, projector); } UpdateInfo(); } mldemos-0.4.3/MLDemos/mlsaving.cpp000066400000000000000000000726761172143270300170240ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include #include #include #include #include #include #include #include "classifier.h" #include "regressor.h" #include using namespace std; void MLDemos::SaveLayoutOptions() { QCoreApplication::setOrganizationDomain("b4silio"); QCoreApplication::setOrganizationName("b4silio"); QCoreApplication::setApplicationName("MLDemos"); QSettings settings; settings.beginGroup("Gui"); settings.setValue("geometry", saveGeometry()); settings.setValue("windowState", saveState()); settings.setValue("algoGeometry", algorithmWidget->saveGeometry()); settings.setValue("drawGeometry", drawToolbarWidget->saveGeometry()); settings.setValue("displayGeometry", displayDialog->saveGeometry()); settings.setValue("statsGeometry", statsDialog->saveGeometry()); settings.setValue("compareGeometry", compareWidget->saveGeometry()); settings.setValue("algoTab", algorithmOptions->tabWidget->currentIndex()); settings.setValue("ShowAlgoOptions", algorithmWidget->isVisible()); settings.setValue("ShowCompare", compareWidget->isVisible()); settings.setValue("ShowDrawOptions", drawToolbarWidget->isVisible()); settings.setValue("ShowDisplayOptions", displayDialog->isVisible()); settings.setValue("ShowStatsOptions", statsDialog->isVisible()); settings.setValue("ShowToolbar", ui.actionShow_Toolbar->isChecked()); settings.setValue("SmallIcons", ui.actionSmall_Icons->isChecked()); // settings.setValue("canvasType", ui.canvasTypeCombo->currentIndex()); settings.endGroup(); settings.beginGroup("displayOptions"); settings.setValue("infoCheck", displayOptions->infoCheck->isChecked()); settings.setValue("mapCheck", displayOptions->mapCheck->isChecked()); settings.setValue("modelCheck", displayOptions->modelCheck->isChecked()); settings.setValue("samplesCheck", displayOptions->samplesCheck->isChecked()); settings.setValue("gridCheck", displayOptions->gridCheck->isChecked()); settings.setValue("spinZoom", displayOptions->spinZoom->value()); settings.endGroup(); settings.beginGroup("drawingOptions"); settings.setValue("infoCheck", drawToolbarContext1->randCombo->currentIndex()); settings.setValue("spinCount", drawToolbarContext1->spinCount->value()); settings.setValue("spinSize", drawToolbarContext1->spinSize->value()); settings.setValue("spinAngle", drawToolbarContext2->spinAngle->value()); settings.setValue("spinSigmaX", drawToolbarContext2->spinSigmaX->value()); settings.setValue("spinSigmaY", drawToolbarContext2->spinSigmaY->value()); settings.setValue("spinObsAngle", drawToolbarContext3->spinAngle->value()); settings.setValue("spinObsSigmaX", drawToolbarContext3->spinSigmaX->value()); settings.setValue("spinObsSigmaY", drawToolbarContext3->spinSigmaY->value()); settings.setValue("spinObsPowerX", drawToolbarContext3->spinPowerX->value()); settings.setValue("spinObsPowerY", drawToolbarContext3->spinPowerY->value()); settings.setValue("spinObsRepulsionX", drawToolbarContext3->spinRepulsionX->value()); settings.setValue("spinObsRepulsionY", drawToolbarContext3->spinRepulsionY->value()); settings.setValue("spinRadius", drawToolbarContext4->spinRadius->value()); settings.setValue("spinAlpha", drawToolbarContext4->spinAlpha->value()); settings.setValue("eraseCheck", drawToolbar->eraseButton->isChecked()); settings.setValue("sprayCheck", drawToolbar->sprayButton->isChecked()); settings.setValue("singleCheck", drawToolbar->singleButton->isChecked()); settings.setValue("ellipseCheck", drawToolbar->ellipseButton->isChecked()); settings.setValue("lineCheck", drawToolbar->lineButton->isChecked()); settings.setValue("trajectoryCheck", drawToolbar->trajectoryButton->isChecked()); settings.setValue("obstacleCheck", drawToolbar->obstacleButton->isChecked()); settings.setValue("paintCheck", drawToolbar->paintButton->isChecked()); settings.setValue("infoCheck", drawToolbarContext1->randCombo->currentIndex()); settings.endGroup(); settings.beginGroup("classificationOptions"); settings.setValue("positiveClass", optionsClassify->positiveSpin->value()); settings.setValue("foldCount", optionsClassify->foldCountSpin->value()); settings.setValue("trainRatio", optionsClassify->traintestRatioCombo->currentIndex()); settings.setValue("tab", optionsClassify->tabWidget->currentIndex()); settings.endGroup(); settings.beginGroup("regressionOptions"); settings.setValue("foldCount", optionsRegress->foldCountSpin->value()); settings.setValue("trainRatio", optionsRegress->traintestRatioCombo->currentIndex()); settings.setValue("tab", optionsRegress->tabWidget->currentIndex()); settings.endGroup(); settings.beginGroup("dynamicalOptions"); settings.setValue("centerType", optionsDynamic->centerCombo->currentIndex()); settings.setValue("zeroCheck", optionsDynamic->zeroCheck->isChecked()); settings.setValue("resampleType", optionsDynamic->resampleCombo->currentIndex()); settings.setValue("resampleCount", optionsDynamic->resampleSpin->value()); settings.setValue("obstacleType", optionsDynamic->obstacleCombo->currentIndex()); settings.setValue("dT", optionsDynamic->dtSpin->value()); settings.setValue("tab", optionsDynamic->tabWidget->currentIndex()); settings.setValue("colorCheck", optionsDynamic->colorCheck->isChecked()); settings.endGroup(); settings.beginGroup("compareOptions"); settings.setValue("foldCount", optionsCompare->foldCountSpin->value()); settings.setValue("trainRatio", optionsCompare->traintestRatioCombo->currentIndex()); settings.endGroup(); settings.beginGroup("clusterOptions"); settings.setValue("tab", optionsCluster->tabWidget->currentIndex()); settings.setValue("trainRatio", optionsCluster->trainRatioCombo->currentIndex()); settings.setValue("optimizeCombo", optionsCluster->optimizeCombo->currentIndex()); settings.endGroup(); settings.beginGroup("maximizeOptions"); settings.setValue("tab", optionsMaximize->tabWidget->currentIndex()); settings.setValue("varianceSpin", optionsMaximize->varianceSpin->value()); settings.setValue("iterationsSpin", optionsMaximize->iterationsSpin->value()); settings.setValue("stoppingSpin", optionsMaximize->stoppingSpin->value()); settings.setValue("benchmarkCombo", optionsMaximize->benchmarkCombo->currentIndex()); settings.endGroup(); settings.beginGroup("projectOptions"); settings.setValue("tab", optionsProject->tabWidget->currentIndex()); settings.endGroup(); settings.beginGroup("statsOptions"); settings.setValue("tab", showStats->tabWidget->currentIndex()); settings.endGroup(); FOR(i,classifiers.size()) { if(!classifiers[i]) continue; settings.beginGroup(QString("plugins::classifiers::") + classifiers[i]->GetName()); classifiers[i]->SaveOptions(settings); settings.endGroup(); } FOR(i,clusterers.size()) { if(!clusterers[i]) continue; settings.beginGroup(QString("plugins::clusterers::") + clusterers[i]->GetName()); clusterers[i]->SaveOptions(settings); settings.endGroup(); } FOR(i,regressors.size()) { if(!regressors[i]) continue; settings.beginGroup(QString("plugins::regressors::") + regressors[i]->GetName()); regressors[i]->SaveOptions(settings); settings.endGroup(); } FOR(i,dynamicals.size()) { if(!dynamicals[i]) continue; settings.beginGroup(QString("plugins::dynamicals::") + dynamicals[i]->GetName()); dynamicals[i]->SaveOptions(settings); settings.endGroup(); } FOR(i,maximizers.size()) { if(!maximizers[i]) continue; settings.beginGroup(QString("plugins::maximizers::") + maximizers[i]->GetName()); maximizers[i]->SaveOptions(settings); settings.endGroup(); } FOR(i,projectors.size()) { if(!projectors[i]) continue; settings.beginGroup(QString("plugins::projectors::") + projectors[i]->GetName()); projectors[i]->SaveOptions(settings); settings.endGroup(); } } void MLDemos::LoadLayoutOptions() { QCoreApplication::setOrganizationDomain("b4silio"); QCoreApplication::setOrganizationName("b4silio"); QCoreApplication::setApplicationName("MLDemos"); QSettings settings; settings.beginGroup("Gui"); if(settings.contains("geometry")) restoreGeometry(settings.value("geometry").toByteArray()); if(settings.contains("windowState")) restoreState(settings.value("windowState").toByteArray()); if(settings.contains("algoGeometry")) algorithmWidget->restoreGeometry(settings.value("algoGeometry").toByteArray()); if(settings.contains("drawGeometry")) drawToolbarWidget->restoreGeometry(settings.value("drawGeometry").toByteArray()); if(settings.contains("displayGeometry")) displayDialog->restoreGeometry(settings.value("displayGeometry").toByteArray()); if(settings.contains("statsGeometry")) statsDialog->restoreGeometry(settings.value("statsGeometry").toByteArray()); if(settings.contains("compareGeometry")) compareWidget->restoreGeometry(settings.value("compareGeometry").toByteArray()); #ifdef MACX // ugly hack to avoid resizing problems on the mac if(height() < 400) resize(width(),400); if(algorithmWidget->height() < 220) algorithmWidget->resize(636,220); #endif // MACX if(settings.contains("algoTab")) algorithmOptions->tabWidget->setCurrentIndex(settings.value("algoTab").toInt()); if(settings.contains("ShowAlgoOptions")) algorithmWidget->setVisible(settings.value("ShowAlgoOptions").toBool()); if(settings.contains("ShowCompare")) compareWidget->setVisible(settings.value("ShowCompare").toBool()); if(settings.contains("ShowDrawOptions")) drawToolbarWidget->setVisible(settings.value("ShowDrawOptions").toBool()); if(settings.contains("ShowDisplayOptions")) displayDialog->setVisible(settings.value("ShowDisplayOptions").toBool()); if(settings.contains("ShowStatsOptions")) statsDialog->setVisible(settings.value("ShowStatsOptions").toBool()); if(settings.contains("ShowToolbar")) ui.actionShow_Toolbar->setChecked(settings.value("ShowToolbar").toBool()); if(settings.contains("SmallIcons")) ui.actionSmall_Icons->setChecked(settings.value("SmallIcons").toBool()); // if(settings.contains("canvasType")) ui.canvasTypeCombo->setCurrentIndex(settings.value("canvasType").toInt()); settings.endGroup(); actionAlgorithms->setChecked(algorithmWidget->isVisible()); actionCompare->setChecked(compareWidget->isVisible()); actionDrawSamples->setChecked(drawToolbarWidget->isVisible()); actionDisplayOptions->setChecked(displayDialog->isVisible()); actionShowStats->setChecked(statsDialog->isVisible()); settings.beginGroup("displayOptions"); if(settings.contains("infoCheck")) displayOptions->infoCheck->setChecked(settings.value("infoCheck").toBool()); if(settings.contains("mapCheck")) displayOptions->mapCheck->setChecked(settings.value("mapCheck").toBool()); if(settings.contains("modelCheck")) displayOptions->modelCheck->setChecked(settings.value("modelCheck").toBool()); if(settings.contains("samplesCheck")) displayOptions->samplesCheck->setChecked(settings.value("samplesCheck").toBool()); if(settings.contains("gridCheck")) displayOptions->gridCheck->setChecked(settings.value("gridCheck").toBool()); if(settings.contains("spinZoom")) displayOptions->spinZoom->setValue(settings.value("spinZoom").toFloat()); //if(settings.contains("xDimIndex")) displayOptions->xDimIndex->setValue(settings.value("xDimIndex").toInt()); //if(settings.contains("yDimIndex")) displayOptions->yDimIndex->setValue(settings.value("yDimIndex").toInt()); settings.endGroup(); settings.beginGroup("drawingOptions"); if(settings.contains("infoCheck")) drawToolbarContext1->randCombo->setCurrentIndex(settings.value("infoCheck").toInt()); if(settings.contains("spinAngle")) drawToolbarContext2->spinAngle->setValue(settings.value("spinAngle").toFloat()); if(settings.contains("spinSize")) drawToolbarContext1->spinSize->setValue(settings.value("spinSize").toFloat()); if(settings.contains("spinCount")) drawToolbarContext1->spinCount->setValue(settings.value("spinCount").toFloat()); if(settings.contains("spinSigmaX")) drawToolbarContext2->spinSigmaX->setValue(settings.value("spinSigmaX").toFloat()); if(settings.contains("spinSigmaY")) drawToolbarContext2->spinSigmaY->setValue(settings.value("spinSigmaY").toFloat()); if(settings.contains("spinObsAngle")) drawToolbarContext3->spinAngle->setValue(settings.value("spinObsAngle").toFloat()); if(settings.contains("spinObsSigmaX")) drawToolbarContext3->spinSigmaX->setValue(settings.value("spinObsSigmaX").toFloat()); if(settings.contains("spinObsSigmaY")) drawToolbarContext3->spinSigmaY->setValue(settings.value("spinObsSigmaY").toFloat()); if(settings.contains("spinObsPowerX")) drawToolbarContext3->spinPowerX->setValue(settings.value("spinObsPowerX").toInt()); if(settings.contains("spinObsPowerY")) drawToolbarContext3->spinPowerY->setValue(settings.value("spinObsPowerY").toInt()); if(settings.contains("spinObsRepulsionX")) drawToolbarContext3->spinRepulsionX->setValue(settings.value("spinObsRepulsionX").toFloat()); if(settings.contains("spinObsRepulsionY")) drawToolbarContext3->spinRepulsionY->setValue(settings.value("spinObsRepulsionY").toFloat()); if(settings.contains("spinRadius")) drawToolbarContext4->spinRadius->setValue(settings.value("spinRadius").toFloat()); if(settings.contains("spinAlpha")) drawToolbarContext4->spinAlpha->setValue(settings.value("spinAlpha").toFloat()); if(settings.contains("eraseCheck")) drawToolbar->eraseButton->setChecked(settings.value("eraseCheck").toBool()); if(settings.contains("sprayCheck")) drawToolbar->sprayButton->setChecked(settings.value("sprayCheck").toBool()); if(settings.contains("singleCheck")) drawToolbar->singleButton->setChecked(settings.value("singleCheck").toBool()); if(settings.contains("ellipseCheck")) drawToolbar->ellipseButton->setChecked(settings.value("ellipseCheck").toBool()); if(settings.contains("lineCheck")) drawToolbar->lineButton->setChecked(settings.value("lineCheck").toBool()); if(settings.contains("trajectoryCheck")) drawToolbar->trajectoryButton->setChecked(settings.value("trajectoryCheck").toBool()); if(settings.contains("obstacleCheck")) drawToolbar->obstacleButton->setChecked(settings.value("obstacleCheck").toBool()); if(settings.contains("paintCheck")) drawToolbar->paintButton->setChecked(settings.value("paintCheck").toBool()); settings.endGroup(); settings.beginGroup("classificationOptions"); if(settings.contains("positiveClass")) optionsClassify->positiveSpin->setValue(settings.value("positiveClass").toFloat()); if(settings.contains("foldCount")) optionsClassify->foldCountSpin->setValue(settings.value("foldCount").toFloat()); if(settings.contains("trainRatio")) optionsClassify->traintestRatioCombo->setCurrentIndex(settings.value("trainRatio").toInt()); if(settings.contains("tab")) optionsClassify->tabWidget->setCurrentIndex(settings.value("tab").toInt()); settings.endGroup(); settings.beginGroup("regressionOptions"); if(settings.contains("foldCount")) optionsRegress->foldCountSpin->setValue(settings.value("foldCount").toFloat()); if(settings.contains("trainRatio")) optionsRegress->traintestRatioCombo->setCurrentIndex(settings.value("trainRatio").toInt()); if(settings.contains("tab")) optionsRegress->tabWidget->setCurrentIndex(settings.value("tab").toInt()); settings.endGroup(); settings.beginGroup("dynamicalOptions"); if(settings.contains("centerType")) optionsDynamic->centerCombo->setCurrentIndex(settings.value("centerType").toInt()); if(settings.contains("zeroCheck")) optionsDynamic->zeroCheck->setChecked(settings.value("zeroCheck").toBool()); if(settings.contains("resampleType")) optionsDynamic->resampleCombo->setCurrentIndex(settings.value("resampleType").toInt()); if(settings.contains("resampleCount")) optionsDynamic->resampleSpin->setValue(settings.value("resampleCount").toFloat()); if(settings.contains("obstacleType")) optionsDynamic->obstacleCombo->setCurrentIndex(settings.value("obstacleType").toInt()); if(settings.contains("dT")) optionsDynamic->dtSpin->setValue(settings.value("dT").toFloat()); if(settings.contains("tab")) optionsDynamic->tabWidget->setCurrentIndex(settings.value("tab").toInt()); if(settings.contains("colorCheck")) optionsDynamic->colorCheck->setChecked(settings.value("colorCheck").toBool()); settings.endGroup(); settings.beginGroup("compareOptions"); if(settings.contains("foldCount")) optionsCompare->foldCountSpin->setValue(settings.value("foldCount").toFloat()); if(settings.contains("trainRatio")) optionsCompare->traintestRatioCombo->setCurrentIndex(settings.value("trainRatio").toInt()); settings.endGroup(); settings.beginGroup("clusterOptions"); if(settings.contains("tab")) optionsCluster->tabWidget->setCurrentIndex(settings.value("tab").toInt()); if(settings.contains("trainRatio")) optionsCluster->trainRatioCombo->setCurrentIndex(settings.value("trainRatio").toInt()); if(settings.contains("optimizeCombo")) optionsCluster->optimizeCombo->setCurrentIndex(settings.value("optimizeCombo").toInt()); settings.endGroup(); settings.beginGroup("maximizeOptions"); if(settings.contains("tab")) optionsMaximize->tabWidget->setCurrentIndex(settings.value("tab").toInt()); if(settings.contains("varianceSpin")) optionsMaximize->varianceSpin->setValue(settings.value("varianceSpin").toDouble()); if(settings.contains("iterationsSpin")) optionsMaximize->iterationsSpin->setValue(settings.value("iterationsSpin").toInt()); if(settings.contains("stoppingSpin")) optionsMaximize->stoppingSpin->setValue(settings.value("stoppingSpin").toDouble()); if(settings.contains("benchmarkCombo")) optionsMaximize->benchmarkCombo->setCurrentIndex(settings.value("benchmarkCombo").toInt()); settings.endGroup(); settings.beginGroup("projectOptions"); if(settings.contains("tab")) optionsProject->tabWidget->setCurrentIndex(settings.value("tab").toInt()); settings.endGroup(); settings.beginGroup("statsOptions"); if(settings.contains("tab")) showStats->tabWidget->setCurrentIndex(settings.value("tab").toInt()); settings.endGroup(); FOR(i,classifiers.size()) { if(!classifiers[i]) continue; settings.beginGroup(QString("plugins::classifiers::") + classifiers[i]->GetName()); classifiers[i]->LoadOptions(settings); settings.endGroup(); } FOR(i,clusterers.size()) { if(!clusterers[i]) continue; settings.beginGroup(QString("plugins::clusterers::") + clusterers[i]->GetName()); clusterers[i]->LoadOptions(settings); settings.endGroup(); } FOR(i,regressors.size()) { if(!regressors[i]) continue; settings.beginGroup(QString("plugins::regressors::") + regressors[i]->GetName()); regressors[i]->LoadOptions(settings); settings.endGroup(); } FOR(i,dynamicals.size()) { if(!dynamicals[i]) continue; settings.beginGroup(QString("plugins::dynamicals::") + dynamicals[i]->GetName()); dynamicals[i]->LoadOptions(settings); settings.endGroup(); } FOR(i,maximizers.size()) { if(!maximizers[i]) continue; settings.beginGroup(QString("plugins::maximizers::") + maximizers[i]->GetName()); maximizers[i]->LoadOptions(settings); settings.endGroup(); } FOR(i,projectors.size()) { if(!projectors[i]) continue; settings.beginGroup(QString("plugins::projectors::") + projectors[i]->GetName()); projectors[i]->LoadOptions(settings); settings.endGroup(); } canvas->repaint(); } void MLDemos::SaveParams( QString filename ) { if(!classifier && !regressor && !clusterer && !dynamical && !maximizer) return; QFile file(filename); file.open(QFile::WriteOnly | QFile::Append); QTextStream out(&file); if(!file.isOpen()) return; if(!canvas->data->GetCount()) out << "0 2\n"; char groupName[255]; if(canvas->dimNames.size()) { out << "headers" << " " << canvas->dimNames.size(); FOR(i, canvas->dimNames.size()) { QString header = canvas->dimNames.at(i); // we take out all spaces as they're really not nice for parsing the headers afterwards header.replace("\n", "_"); header.replace(" ", "_"); header.replace("\t", "_"); out << " " << header; } out << "\n"; } if(classifier) { int tab = optionsClassify->tabWidget->currentIndex(); sprintf(groupName,"classificationOptions"); out << groupName << ":" << "tab" << " " << optionsClassify->tabWidget->currentIndex() << "\n"; out << groupName << ":" << "positiveClass" << " " << optionsClassify->positiveSpin->value() << "\n"; if(tab < classifiers.size() && classifiers[tab]) { classifiers[tab]->SaveParams(out); } } if(regressor) { int tab = optionsRegress->tabWidget->currentIndex(); sprintf(groupName,"regressionOptions"); out << groupName << ":" << "tab" << " " << optionsRegress->tabWidget->currentIndex() << "\n"; out << groupName << ":" << "outputDimCombo" << " " << optionsRegress->outputDimCombo->currentIndex() << "\n"; if(tab < regressors.size() && regressors[tab]) { regressors[tab]->SaveParams(out); } } if(dynamical) { int tab = optionsDynamic->tabWidget->currentIndex(); sprintf(groupName,"dynamicalOptions"); out << groupName << ":" << "centerType" << " " << optionsDynamic->centerCombo->currentIndex() << "\n"; out << groupName << ":" << "zeroCheck" << " " << optionsDynamic->zeroCheck->isChecked() << "\n"; out << groupName << ":" << "resampleType" << " " << optionsDynamic->resampleCombo->currentIndex() << "\n"; out << groupName << ":" << "resampleCount" << " " << optionsDynamic->resampleSpin->value() << "\n"; out << groupName << ":" << "obstacleType" << " " << optionsDynamic->obstacleCombo->currentIndex() << "\n"; out << groupName << ":" << "dT" << " " << optionsDynamic->dtSpin->value() << "\n"; out << groupName << ":" << "colorCheck" << " " << optionsDynamic->colorCheck->isChecked() << "\n"; out << groupName << ":" << "tab" << " " << optionsDynamic->tabWidget->currentIndex() << "\n"; if(tab < dynamicals.size() && dynamicals[tab]) { dynamicals[tab]->SaveParams(out); } } if(clusterer) { int tab = optionsCluster->tabWidget->currentIndex(); sprintf(groupName,"clusterOptions"); out << groupName << ":" << "tab" << " " << optionsCluster->tabWidget->currentIndex() << "\n"; out << groupName << ":" << "trainRatio" << " " << optionsCluster->trainRatioCombo->currentIndex() << "\n"; out << groupName << ":" << "optimizeCombo" << " " << optionsCluster->optimizeCombo->currentIndex() << "\n"; if(tab < clusterers.size() && clusterers[tab]) { clusterers[tab]->SaveParams(out); } } if(maximizer) { int tab = optionsMaximize->tabWidget->currentIndex(); double variance = optionsMaximize->varianceSpin->value(); sprintf(groupName,"maximizationOptions"); out << groupName << ":" << "tab" << " " << optionsMaximize->tabWidget->currentIndex() << "\n"; out << groupName << ":" << "gaussVarianceSpin" << " " << optionsMaximize->varianceSpin->value() << "\n"; out << groupName << ":" << "iterationsSpin" << " " << optionsMaximize->iterationsSpin->value() << "\n"; out << groupName << ":" << "stoppingSpin" << " " << optionsMaximize->stoppingSpin->value() << "\n"; out << groupName << ":" << "benchmarkCombo" << " " << optionsMaximize->benchmarkCombo->currentIndex() << "\n"; if(tab < maximizers.size() && maximizers[tab]) { maximizers[tab]->SaveParams(out); } } if(projector) { int tab = optionsProject->tabWidget->currentIndex(); sprintf(groupName,"projectOptions"); out << groupName << ":" << "tab" << " " << optionsProject->tabWidget->currentIndex() << "\n"; if(tab < projectors.size() && projectors[tab]) { projectors[tab]->SaveParams(out); } } } bool startsWith(char *a, char *b) { bool yeah = true; for (int i=0; i> sampleCnt; in >> size; QString line; //char line[255]; float value; char classGroup[255]; char regrGroup[255]; char dynGroup[255]; char clustGroup[255]; char maximGroup[255]; char projGroup[255]; sprintf(classGroup,"classificationOptions"); sprintf(regrGroup,"regressionOptions"); sprintf(dynGroup,"dynamicalOptions"); sprintf(clustGroup,"clusteringOptions"); sprintf(maximGroup,"maximizationOptions"); sprintf(projGroup,"projectOptions"); // we skip the samples themselves qDebug() << "Skipping "<< sampleCnt <<" samples" << endl; FOR(i, sampleCnt) line = in.readLine(); bool bClass = false, bRegr = false, bDyn = false, bClust = false, bMaxim = false, bProj = false; qDebug() << "Loading parameter list" << endl; int tab = 0; while(!in.atEnd()) { in >> line; in >> value; // qDebug() << line << " " << value << endl; if(line.startsWith("headers")) { int headerCount = value; canvas->dimNames.clear(); FOR(i, headerCount) { QString header; in >> header; canvas->dimNames << header; } //qDebug() << "dimensions: " << dimensionNames; canvas->dimNames; } if(line.startsWith(classGroup)) { bClass = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabClass); if(line.endsWith("tab")) optionsClassify->tabWidget->setCurrentIndex(tab = (int)value); if(line.endsWith("positiveClass")) optionsClassify->positiveSpin->setValue((int)value); if(tab < classifiers.size() && classifiers[tab]) classifiers[tab]->LoadParams(line,value); } if(line.startsWith(regrGroup)) { bRegr = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabRegr); if(line.endsWith("tab")) optionsRegress->tabWidget->setCurrentIndex(tab = (int)value); if(line.endsWith("outputDimCombo")) optionsRegress->outputDimCombo->setCurrentIndex((int)value); if(tab < regressors.size() && regressors[tab]) regressors[tab]->LoadParams(line,value); } if(line.startsWith(dynGroup)) { bDyn = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabDyn); if(line.endsWith("centerType")) optionsDynamic->centerCombo->setCurrentIndex((int)value); if(line.endsWith("zeroCheck")) optionsDynamic->zeroCheck->setChecked((int)value); if(line.endsWith("resampleType")) optionsDynamic->resampleCombo->setCurrentIndex((int)value); if(line.endsWith("resampleCount")) optionsDynamic->resampleSpin->setValue((int)value); if(line.endsWith("obstacleType")) optionsDynamic->obstacleCombo->setCurrentIndex((int)value); if(line.endsWith("dT")) optionsDynamic->dtSpin->setValue((float)value); if(line.endsWith("colorCheck")) optionsDynamic->colorCheck->setChecked((int)value); if(line.endsWith("tab")) optionsDynamic->tabWidget->setCurrentIndex(tab = (int)value); if(tab < dynamicals.size() && dynamicals[tab]) dynamicals[tab]->LoadParams(line,value); } if(line.startsWith(clustGroup)) { bClust = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabClust); if(line.endsWith("tab")) optionsCluster->tabWidget->setCurrentIndex(tab = (int)value); if(line.endsWith("trainRatio")) optionsCluster->trainRatioCombo->setCurrentIndex(tab = (int)value); if(line.endsWith("optimizeCombo")) optionsCluster->optimizeCombo->setCurrentIndex(tab = (int)value); if(tab < clusterers.size() && clusterers[tab]) clusterers[tab]->LoadParams(line,value); } if(line.startsWith(maximGroup)) { bMaxim = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabMax); if(line.endsWith("tab")) optionsMaximize->tabWidget->setCurrentIndex(tab = (int)value); if(line.endsWith("gaussVarianceSpin")) optionsMaximize->varianceSpin->setValue((double)value); if(line.endsWith("iterationsSpin")) optionsMaximize->iterationsSpin->setValue((int)value); if(line.endsWith("stoppingSpin")) optionsMaximize->stoppingSpin->setValue((double)value); if(line.endsWith("benchmarkCombo")) optionsMaximize->benchmarkCombo->setCurrentIndex(tab = (int)value); if(tab < maximizers.size() && maximizers[tab]) maximizers[tab]->LoadParams(line,value); } if(line.startsWith(projGroup)) { bProj = true; algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabProj); if(line.endsWith("tab")) optionsProject->tabWidget->setCurrentIndex(tab = (int)value); if(tab < projectors.size() && projectors[tab]) projectors[tab]->LoadParams(line,value); } } ResetPositiveClass(); ManualSelectionUpdated(); InputDimensionsUpdated(); if(bClass) Classify(); if(bRegr) Regression(); if(bDyn) Dynamize(); if(bClust) Cluster(); if(bMaxim) Maximize(); if(bProj) Project(); actionAlgorithms->setChecked(algorithmWidget->isVisible()); } mldemos-0.4.3/MLDemos/mlstats.cpp000066400000000000000000000204711172143270300166550ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include "basicMath.h" #include "classifier.h" #include "regressor.h" #include "clusterer.h" #include #include #include #include #include #include #include #include using namespace std; void MLDemos::MouseOnRoc(QMouseEvent *event) { int e; switch( event->button()) { case Qt::LeftButton: e = EVENT_LBUTTONUP; break; case Qt::RightButton: e = EVENT_RBUTTONUP; break; } //roc_on_mouse(e, event->x(), event->y(), 0, 0); //rocWidget->ShowImage(GetRocImage()); //statsDialog->repaint(); } void MLDemos::ShowRoc() { if(!classifier) return; SetROCInfo(); actionShowStats->setChecked(true); showStats->tabWidget->setCurrentWidget(showStats->rocTab); ShowStatsDialog(); } void MLDemos::ShowCross() { if(!classifier && !regressor) return; SetCrossValidationInfo(); actionShowStats->setChecked(true); showStats->tabWidget->setCurrentWidget(showStats->crossvalidTab); ShowStatsDialog(); } void MLDemos::StatsChanged() { int tab = showStats->tabWidget->currentIndex(); switch(tab) { case 0: UpdateInfo(); break; case 1: SetROCInfo(); break; case 2: SetCrossValidationInfo(); break; } } void PaintData(std::vector data, QPixmap &pm) { QPainter painter(&pm); painter.fillRect(pm.rect(), Qt::white); int w = pm.width(); int h = pm.height(); int cnt = data.size(); int pad = 10; QPointF oldPoint; double minVal = FLT_MAX; double maxVal = -FLT_MAX; for(int i=0; i< data.size(); i++) { if(minVal > data[i]) minVal = data[i]; if(maxVal < data[i]) maxVal = data[i]; } if (minVal == maxVal) { minVal = 0; } painter.setBrush(Qt::NoBrush); painter.setPen(QPen(QColor(200,200,200), 0.5)); int steps = 10; for(int i=0; i<=steps; i++) { painter.drawLine(QPoint(0, i/(float)steps*(h-2*pad) + pad), QPoint(w, i/(float)steps*(h-2*pad) + pad)); painter.drawLine(QPoint(i/(float)steps*w, 0), QPoint(i/(float)steps*w, h)); } painter.setRenderHint(QPainter::Antialiasing); painter.setPen(QPen(Qt::black, 1.5)); for(int i=0; i< data.size(); i++) { float value = data[i]; if (value != value) continue; float x = i/(float)cnt*w; float y = (1 - (value-minVal)/(maxVal - minVal)) * (float)(h-2*pad) + pad; QPointF point(x, y); if(i) painter.drawLine(oldPoint, point); //painter.drawEllipse(point, 3, 3); oldPoint = point; } painter.setPen(QPen(Qt::black, 0.5)); painter.setBrush(QColor(255,255,255,200)); painter.drawRect(QRect(w - 100 - 15,h - 55,110,45)); painter.setPen(QPen(Qt::black, 1)); painter.drawText(QPointF(w - 107, h-57+20), QString("start: %1").arg(data[0], 3)); painter.drawText(QPointF(w - 107, h-57+40), QString("end: %1").arg(data[data.size()-1], 3)); } void MLDemos::SetROCInfo() { QSize size(showStats->rocWidget->width(),showStats->rocWidget->height()); if(classifier && bIsRocNew) { QPixmap rocImage = RocImage(classifier->rocdata, classifier->roclabels, size); bIsRocNew = false; // rocImage.save("roc.png"); rocWidget->ShowImage(rocImage); } if(maximizer) { vector history = maximizer->HistoryValue(); vector data;data.resize(history.size()); FOR(i, data.size()) data[i] = history[i]; if(!data.size()) return; QPixmap pixmap(size); PaintData(data, pixmap); rocWidget->ShowImage(pixmap); } } void MLDemos::SetCrossValidationInfo() { if(!bIsCrossNew) return; std::vector fmeasures; if(classifier) fmeasures = classifier->crossval; else if(regressor) fmeasures = regressor->crossval; if(!fmeasures.size()) return; char txt[255]; QString text; text += "Cross-Validation\n"; float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = classifier ? optionsClassify->traintestRatioCombo->currentIndex() : optionsRegress->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; if(classifier) sprintf(txt, "%d folds\n", optionsClassify->foldCountSpin->value()); else sprintf(txt, "%d folds\n", optionsRegress->foldCountSpin->value()); text += txt; sprintf(txt,"%d train, %d test samples", (int)(canvas->data->GetCount()*trainRatio), canvas->data->GetCount() - (int)(canvas->data->GetCount()*trainRatio)); text += txt + QString("\n\n"); text += classifier ? QString("Classification Performance:\n\n") : QString("Regression Error:\n\n"); FOR(i, fmeasures.size()) { fvec meanStd = MeanStd(fmeasures[i]); fvec quartiles = Quartiles(fmeasures[i]); text += !i ? "Training\n" : "Testing\n"; sprintf(txt,"%.3f %.3f", meanStd[0], meanStd[1]); text += txt + QString(" (meanstd)\n"); sprintf(txt,"%.3f %.3f %.3f %.3f %.3f", quartiles[0], quartiles[1], quartiles[2], quartiles[3], quartiles[4]); text += txt + QString(" (quartiles)\n"); text += "\n\n"; } showStats->crossvalidText->setText(text); QSize boxSize(showStats->crossvalidWidget->width(),showStats->crossvalidWidget->height()); QPixmap boxplot = BoxPlot(fmeasures, boxSize); // boxplot.save("boxplot.png"); bIsCrossNew = false; showStats->crossvalidImage->setPixmap(boxplot); } void MLDemos::UpdateInfo() { // dataset information int count = canvas->data->GetCount(); int pcount = 0, ncount = 0; ivec labels = canvas->data->GetLabels(); int posClass = optionsClassify->positiveSpin->value(); FOR(i, labels.size()) { if(labels[i] == posClass) ++pcount; else ++ncount; } // min/max, mean/variance vector samples = canvas->data->GetSamples(); fvec sMin,sMax,sMean,sSigma; sMin.resize(2,FLT_MAX); sMax.resize(2,-FLT_MAX); sMean.resize(2,0); sSigma.resize(4,0); if(samples.size()) { FOR(i,samples.size()) { sMin[0] = min(sMin[0],samples[i][0]); sMin[1] = min(sMin[1],samples[i][1]); sMax[0] = max(sMax[0],samples[i][0]); sMax[1] = max(sMax[1],samples[i][1]); sMean += samples[i]; } sMean /= samples.size(); FOR(i, samples.size()) { sSigma[0] += (samples[i][0]-sMean[0])*(samples[i][0]-sMean[0]); sSigma[1] += (samples[i][0]-sMean[0])*(samples[i][1]-sMean[1]); sSigma[3] += (samples[i][1]-sMean[1])*(samples[i][1]-sMean[1]); } sSigma[0] = sqrtf(sSigma[0]/samples.size()); sSigma[1] = sqrtf(sSigma[1]/samples.size()); if(sSigma[1] != sSigma[1]) sSigma[1] = 0; sSigma[2] = sSigma[1]; sSigma[3] = sqrtf(sSigma[3]/samples.size()); } else { sMin.clear();sMax.clear(); sMin.resize(2,0); sMax.resize(2,0); } QString information; if(classifier) { information += "Classification Performance:\n" + lastTrainingInfo; information += "\nClassifier: " + QString(classifier->GetInfoString()); } if(regressor) information += "\nRegressor: " + QString(regressor->GetInfoString()); if(clusterer) information += "\nClusterer: " + QString(clusterer->GetInfoString()); if(dynamical) information += "\nDynamical: " + QString(dynamical->GetInfoString()); if(maximizer) information += "\nMaximizer: " + QString(maximizer->GetInfoString()); information += "\nCurrent Dataset:\n"; char string[255]; sprintf(string, " %d Samples\n %d Positives\n %d Negatives\n\n", count, pcount, ncount); information += QString(string); information += " Min - Max Mean , Var\n"; sprintf(string, " %.3f %.3f %.3f , %.3f %.3f\n", sMin[0], sMax[0], sMean[0], sSigma[0], sSigma[1]); sprintf(string, "%s %.3f %.3f %.3f , %.3f %.3f\n", string, sMin[1], sMax[1], sMean[1], sSigma[2], sSigma[3]); information += string; showStats->infoText->setText(information); } mldemos-0.4.3/MLDemos/mltrain.cpp000066400000000000000000001062601172143270300166350ustar00rootroot00000000000000/********************************************************************* MLDemos: A User-Friendly visualization toolkit for machine learning Copyright (C) 2010 Basilio Noris Contact: mldemos@b4silio.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #include "mldemos.h" #include "basicMath.h" #include "classifier.h" #include "regressor.h" #include "dynamical.h" #include "clusterer.h" #include "maximize.h" #include "roc.h" #include #include #include #include #include #include #include using namespace std; bool MLDemos::Train(Classifier *classifier, int positive, float trainRatio, bvec trainList) { if(!classifier) return false; ivec labels = canvas->data->GetLabels(); ivec newLabels; std::map binaryClassMap; newLabels.resize(labels.size(), 1); bool bMulticlass = classifier->IsMultiClass(); if(!bMulticlass) { if(positive == 0) { FOR(i, labels.size()) newLabels[i] = (!labels[i] || labels[i] == -1) ? 1 : -1; } else { FOR(i, labels.size()) newLabels[i] = (labels[i] == positive) ? 1 : -1; } bool bHasPositive = false, bHasNegative = false; FOR(i, newLabels.size()) { if(bHasPositive && bHasNegative) break; bHasPositive |= newLabels[i] == 1; bHasNegative |= newLabels[i] == -1; } if((!bHasPositive || !bHasNegative) && !classifier->SingleClass()) return false; } else { newLabels = labels; // int cnt=0; FOR(i, labels.size()) if(!binaryClassMap.count(labels[i])) binaryClassMap[labels[i]] = cnt++; if(binaryClassMap.size() > 2) binaryClassMap.clear(); // standard multiclass, no problems //for(map::iterator it=classMap.begin(); it != classMap.end(); it++); //positive = classMap.begin()->first; //binaryLabels.resize(labels.size()); //FOR(i, labels.size()) binaryLabels[i] = labels[i] == positive ? 1 : 0; } classifier->rocdata.clear(); classifier->roclabels.clear(); lastTrainingInfo = ""; map truePerClass; map falsePerClass; map countPerClass; ivec inputDims = GetInputDimensions(); vector samples = canvas->data->GetSampleDims(inputDims); vector trainSamples, testSamples; ivec trainLabels, testLabels; u32 *perm = 0; int trainCnt, testCnt; if(trainList.size()) { FOR(i, trainList.size()) { if(trainList[i]) { trainSamples.push_back(samples[i]); trainLabels.push_back(newLabels[i]); } else { testSamples.push_back(samples[i]); testLabels.push_back(newLabels[i]); } } trainCnt = trainSamples.size(); testCnt = testSamples.size(); } else { map classCnt, trainClassCnt, testClassCnt; FOR(i, labels.size()) { classCnt[labels[i]]++; } trainCnt = (int)(samples.size()*trainRatio); testCnt = samples.size() - trainCnt; trainSamples.resize(trainCnt); trainLabels.resize(trainCnt); testSamples.resize(testCnt); testLabels.resize(testCnt); perm = randPerm(samples.size()); FOR(i, trainCnt) { trainSamples[i] = samples[perm[i]]; trainLabels[i] = newLabels[perm[i]]; trainClassCnt[trainLabels[i]]++; } for(int i=trainCnt; i::iterator it=classCnt.begin();it!=classCnt.end();it++) { if(!trainClassCnt.count(it->first)) { FOR(i, testSamples.size()) { if(testLabels[i] != it->first) continue; <<<<<<< HEAD trainSamples[i] = testSamples[i]; trainLabels[i] = testLabels[i]; ======= trainSamples.push_back(testSamples[i]); trainLabels.push_back(testLabels[i]); >>>>>>> devel testSamples.erase(testSamples.begin() + i); testLabels.erase(testLabels.begin() + i); trainCnt++; testCnt--; break; } } } } classifier->Train(trainSamples, trainLabels); // we generate the roc curve for this guy bool bTrueMulti = bMulticlass; vector rocData; FOR(i, trainSamples.size()) { int label = trainLabels[i]; if(bMulticlass && binaryClassMap.size()) label = binaryClassMap[label]; if(bMulticlass) { fvec res = classifier->TestMulti(trainSamples[i]); if(res.size() == 1) { rocData.push_back(f32pair(res[0], label)); float resp = res[0]; if(resp > 0 && label == 1) truePerClass[1]++; else if(resp > 0 && label != 1) falsePerClass[0]++; else if(label == 1) falsePerClass[1]++; else truePerClass[0]++; bTrueMulti = false; } else { int maxClass = 0; for(int j=1; jinverseMap[maxClass], label)); int c = classifier->inverseMap[maxClass]; if(label != c) falsePerClass[c]++; else truePerClass[c]++; } } else { float resp = classifier->Test(trainSamples[i]); rocData.push_back(f32pair(resp, label)); if(resp > 0 && label == 1) truePerClass[1]++; else if(resp > 0 && label != 1) falsePerClass[0]++; else if(label == 1) falsePerClass[1]++; else truePerClass[0]++; } if(bMulticlass) countPerClass[label]++; else countPerClass[(label==1)?1:0]++; } if(!bTrueMulti) rocData = FixRocData(rocData); classifier->rocdata.push_back(rocData); classifier->roclabels.push_back("training"); lastTrainingInfo += QString("\nTraining Set (%1 samples):\n").arg(trainSamples.size()); int posClass = 1; if(bTrueMulti) { for(map::iterator it = countPerClass.begin(); it != countPerClass.end(); it++) { int c = it->first; int tp = truePerClass[c]; int fp = falsePerClass[c]; float ratio = it->second != 0 ? tp / (float)it->second : 0; lastTrainingInfo += QString("Class %1 (%5 samples): %2 correct (%4%)\n%3 incorrect\n").arg(c).arg(tp).arg(fp).arg((int)(ratio*100)).arg(it->second); } } else { if(truePerClass[1] / (float) countPerClass[1] < 0.25) { posClass = 0; } int tp = posClass ? truePerClass[1] : falsePerClass[1]; int fp = posClass ? falsePerClass[1] : truePerClass[1]; int count = countPerClass[1]; float ratio = count != 0 ? tp/(float)count : 1; lastTrainingInfo += QString("Positive (%4 samples): %1 correct (%3%)\n%2 incorrect\n").arg(tp).arg(fp).arg((int)(ratio*100)).arg(count); tp = posClass ? truePerClass[0] : falsePerClass[0]; fp = posClass ? falsePerClass[0] : truePerClass[0]; count = countPerClass[0]; ratio = count != 0 ? tp/(float)count : 1; lastTrainingInfo += QString("Negative (%4 samples): %1 correct (%3%)\n%2 incorrect\n").arg(tp).arg(fp).arg((int)(ratio*100)).arg(count); } truePerClass.clear(); falsePerClass.clear(); countPerClass.clear(); rocData.clear(); FOR(i, testSamples.size()) { int label = testLabels[i]; if(bMulticlass && binaryClassMap.size()) label = binaryClassMap[label]; if(bMulticlass) { fvec res = classifier->TestMulti(testSamples[i]); if(res.size() == 1) { rocData.push_back(f32pair(res[0], label)); float resp = res[0]; if(resp > 0 && label == 1) truePerClass[1]++; else if(resp > 0 && label != 1) falsePerClass[0]++; else if(label == 1) falsePerClass[1]++; else truePerClass[0]++; bTrueMulti = false; } else { int maxClass = 0; for(int j=1; jinverseMap[maxClass], label)); int c = classifier->inverseMap[maxClass]; if(label != c) falsePerClass[c]++; else truePerClass[c]++; } } else { float resp = classifier->Test(testSamples[i]); rocData.push_back(f32pair(resp, label)); if(resp > 0 && label == 1) truePerClass[1]++; else if(resp > 0 && label != 1) falsePerClass[0]++; else if(label == 1) falsePerClass[1]++; else truePerClass[0]++; } if(bMulticlass) countPerClass[label]++; else countPerClass[(label==1)?1:0]++; } if(!bTrueMulti) rocData = FixRocData(rocData); classifier->rocdata.push_back(rocData); classifier->roclabels.push_back("test"); lastTrainingInfo += QString("\nTesting Set (%1 samples):\n").arg(testSamples.size()); if(bTrueMulti) { for(map::iterator it = countPerClass.begin(); it != countPerClass.end(); it++) { int c = it->first; int tp = truePerClass[c]; int fp = falsePerClass[c]; float ratio = it->second != 0 ? tp / (float)it->second : 0; lastTrainingInfo += QString("Class %1 (%5 samples): %2 correct (%4%)\n%3 incorrect\n").arg(c).arg(tp).arg(fp).arg((int)(ratio*100)).arg(it->second); } } else { int tp = posClass ? truePerClass[1] : falsePerClass[1]; int fp = posClass ? falsePerClass[1] : truePerClass[1]; int count = countPerClass[1]; float ratio = count != 0 ? tp/(float)count : 1; lastTrainingInfo += QString("Positive (%4 samples): %1 correct (%3%)\n%2 incorrect\n").arg(tp).arg(fp).arg((int)(ratio*100)).arg(count); tp = posClass ? truePerClass[0] : falsePerClass[0]; fp = posClass ? falsePerClass[0] : truePerClass[0]; count = countPerClass[0]; ratio = count != 0 ? tp/(float)count : 1; lastTrainingInfo += QString("Negative (%4 samples): %1 correct (%3%)\n%2 incorrect\n").arg(tp).arg(fp).arg((int)(ratio*100)).arg(count); } KILL(perm); bIsRocNew = true; bIsCrossNew = true; SetROCInfo(); return true; } void MLDemos::Train(Regressor *regressor, int outputDim, float trainRatio, bvec trainList) { if(!regressor || !canvas->data->GetCount()) return; ivec inputDims = GetInputDimensions(); int outputIndexInList = -1; if(inputDims.size()==1 && inputDims[0] == outputDim) return; // we dont have enough dimensions for training FOR(i, inputDims.size()) if(outputDim == inputDims[i]) { outputIndexInList = i; break; } vector samples = canvas->data->GetSampleDims(inputDims, outputIndexInList == -1 ? outputDim : -1); ivec labels = canvas->data->GetLabels(); if(!samples.size()) return; int cnt = samples.size(); int dim = samples[0].size(); if(dim < 2) return; regressor->SetOutputDim(outputDim); fvec trainErrors, testErrors; if(trainRatio == 1.f && !trainList.size()) { regressor->Train(samples, labels); trainErrors.clear(); FOR(i, samples.size()) { fvec sample = samples[i]; int dim = sample.size(); fvec res = regressor->Test(sample); float error = fabs(res[0] - sample.back()); trainErrors.push_back(error); } regressor->trainErrors = trainErrors; regressor->testErrors.clear(); } else { int trainCnt = (int)(samples.size()*trainRatio); int testCnt = samples.size() - trainCnt; u32 *perm = randPerm(samples.size()); vector trainSamples, testSamples; ivec trainLabels, testLabels; if(trainList.size()) { FOR(i, trainList.size()) { if(trainList[i]) { trainSamples.push_back(samples[i]); trainLabels.push_back(labels[i]); } else { testSamples.push_back(samples[i]); testLabels.push_back(labels[i]); } } } else { trainSamples.resize(trainCnt); trainLabels.resize(trainCnt); testSamples.resize(testCnt); testLabels.resize(testCnt); FOR(i, trainCnt) { trainSamples[i] = samples[perm[i]]; trainLabels[i] = labels[perm[i]]; } FOR(i, testCnt) { testSamples[i] = samples[perm[i+trainCnt]]; testLabels[i] = labels[perm[i+trainCnt]]; } } regressor->Train(trainSamples, trainLabels); FOR(i, trainCnt) { fvec sample = trainSamples[i]; int dim = sample.size(); fvec res = regressor->Test(sample); float error = fabs(res[0] - sample.back()); trainErrors.push_back(error); } FOR(i, testCnt) { fvec sample = testSamples[i]; int dim = sample.size(); fvec res = regressor->Test(sample); float error = fabs(res[0] - sample.back()); testErrors.push_back(error); qDebug() << " test error: " << i << error; } regressor->trainErrors = trainErrors; regressor->testErrors = testErrors; KILL(perm); } bIsCrossNew = true; } // returns respectively the reconstruction error for the training points individually, per trajectory, and the error to target fvec MLDemos::Train(Dynamical *dynamical) { if(!dynamical) return fvec(); vector samples = canvas->data->GetSamples(); vector sequences = canvas->data->GetSequences(); ivec labels = canvas->data->GetLabels(); if(!samples.size() || !sequences.size()) return fvec(); int dim = samples[0].size(); int count = optionsDynamic->resampleSpin->value(); int resampleType = optionsDynamic->resampleCombo->currentIndex(); int centerType = optionsDynamic->centerCombo->currentIndex(); bool zeroEnding = optionsDynamic->zeroCheck->isChecked(); ivec trajLabels(sequences.size()); FOR(i, sequences.size()) { trajLabels[i] = canvas->data->GetLabel(sequences[i].first); } //float dT = 10.f; // time span between each data frame float dT = optionsDynamic->dtSpin->value(); dynamical->dT = dT; //dT = 10.f; vector< vector > trajectories = canvas->data->GetTrajectories(resampleType, count, centerType, dT, zeroEnding); interpolate(trajectories[0],count); dynamical->Train(trajectories, labels); return Test(dynamical, trajectories, labels); } void MLDemos::Train(Clusterer *clusterer, bvec trainList) { if(!clusterer) return; if(trainList.size()) { vector trainSamples; FOR(i, trainList.size()) { if(trainList[i]) { trainSamples.push_back(canvas->data->GetSample(i)); } } clusterer->Train(trainSamples); } else clusterer->Train(canvas->data->GetSamples()); } void MLDemos::Train(Projector *projector, bvec trainList) { if(!projector) return; if(trainList.size()) { vector trainSamples; ivec trainLabels; FOR(i, trainList.size()) { if(trainList[i]) { trainSamples.push_back(canvas->data->GetSample(i)); trainLabels.push_back(canvas->data->GetLabel(i)); } } projector->Train(trainSamples, trainLabels); } else projector->Train(canvas->data->GetSamples(), canvas->data->GetLabels()); } void MLDemos::Train(Maximizer *maximizer) { if(!maximizer) return; if(canvas->maps.reward.isNull()) return; QImage rewardImage = canvas->maps.reward.toImage(); QRgb *pixels = (QRgb*) rewardImage.bits(); int w = rewardImage.width(); int h = rewardImage.height(); float *data = new float[w*h]; float maxData = 0; FOR(i, w*h) { data[i] = 1.f - qBlue(pixels[i])/255.f; // all data is in a 0-1 range maxData = max(maxData, data[i]); } if(maxData > 0) { FOR(i, w*h) data[i] /= maxData; // we ensure that the data is normalized } fvec startingPoint; if(canvas->targets.size()) { startingPoint = canvas->targets[canvas->targets.size()-1]; QPointF starting = canvas->toCanvasCoords(startingPoint); startingPoint[0] = starting.x()/w; startingPoint[1] = starting.y()/h; } maximizer->Train(data, fVec(w,h), startingPoint); maximizer->age = 0; delete [] data; } void MLDemos::Test(Maximizer *maximizer) { if(!maximizer) return; do { fvec sample = maximizer->Test(maximizer->Maximum()); maximizer->age++; } while(maximizer->age < maximizer->maxAge && maximizer->MaximumValue() < maximizer->stopValue); } // returns respectively the reconstruction error for the training points individually, per trajectory, and the error to target fvec MLDemos::Test(Dynamical *dynamical, vector< vector > trajectories, ivec labels) { if(!dynamical || !trajectories.size()) return fvec(); int dim = trajectories[0][0].size()/2; //(int dim = dynamical->Dim(); float dT = dynamical->dT; fvec sample; sample.resize(dim,0); fvec vTrue; vTrue.resize(dim, 0); fvec xMin(dim, FLT_MAX); fvec xMax(dim, -FLT_MAX); // test each trajectory for errors int errorCnt=0; float errorOne = 0, errorAll = 0; FOR(i, trajectories.size()) { vector t = trajectories[i]; float errorTraj = 0; FOR(j, t.size()) { FOR(d, dim) { sample[d] = t[j][d]; vTrue[d] = t[j][d+dim]; if(xMin[d] > sample[d]) xMin[d] = sample[d]; if(xMax[d] < sample[d]) xMax[d] = sample[d]; } fvec v = dynamical->Test(sample); float error = 0; FOR(d, dim) error += (v[d] - vTrue[d])*(v[d] - vTrue[d]); errorTraj += error; errorCnt++; } errorOne += errorTraj; errorAll += errorTraj / t.size(); } errorOne /= errorCnt; errorAll /= trajectories.size(); fvec res; res.push_back(errorOne); vector endpoints; float errorTarget = 0; // test each trajectory for target fvec pos(dim), end(dim); FOR(i, trajectories.size()) { FOR(d, dim) { pos[d] = trajectories[i].front()[d]; end[d] = trajectories[i].back()[d]; } if(!endpoints.size()) endpoints.push_back(end); else { bool bExists = false; FOR(j, endpoints.size()) { if(endpoints[j] == end) { bExists = true; break; } } if(!bExists) endpoints.push_back(end); } int steps = 500; float eps = FLT_MIN; FOR(j, steps) { fvec v = dynamical->Test(pos); float speed = 0; FOR(d, dim) speed += v[d]*v[d]; speed = sqrtf(speed); if(speed*dT < eps) break; pos += v*dT; } float error = 0; FOR(d, dim) { error += (pos[d] - end[d])*(pos[d] - end[d]); } error = sqrtf(error); errorTarget += error; } errorTarget /= trajectories.size(); res.push_back(errorTarget); fvec xDiff = xMax - xMin; errorTarget = 0; int testCount = 100; FOR(i, testCount) { FOR(d, dim) { pos[d] = ((drand48()*2 - 0.5)*xDiff[d] + xMin[d]); } int steps = 500; float eps = FLT_MIN; FOR(j, steps) { fvec v = dynamical->Test(pos); float speed = 0; FOR(d, dim) speed += v[d]*v[d]; speed = sqrtf(speed); if(speed*dT < eps) break; pos += v*dT; } float minError = FLT_MAX; FOR(j, endpoints.size()) { float error = 0; FOR(d, dim) { error += (pos[d] - endpoints[j][d])*(pos[d] - endpoints[j][d]); } error = sqrtf(error); if(minError > error) minError = error; } errorTarget += minError; } errorTarget /= testCount; res.push_back(errorTarget); return res; } void MLDemos::Compare() { if(!canvas) return; if(!compareOptions.size()) return; QMutexLocker lock(&mutex); drawTimer->Stop(); DEL(clusterer); DEL(regressor); DEL(dynamical); DEL(classifier); DEL(maximizer); DEL(projector); // we start parsing the algorithm list int folds = optionsCompare->foldCountSpin->value(); float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f}; int ratioIndex = optionsCompare->traintestRatioCombo->currentIndex(); float trainRatio = ratios[ratioIndex]; //int positive = optionsCompare->positiveSpin->value(); int positive = 1; compare->Clear(); QProgressDialog progress("Comparing Algorithms", "cancel", 0, folds*compareOptions.size()); progress.show(); FOR(i, compareOptions.size()) { QString string = compareOptions[i]; QTextStream stream(&string); QString line = stream.readLine(); QString paramString = stream.readAll(); if(line.startsWith("Optimization")) { QStringList s = line.split(":"); int tab = s[1].toInt(); if(tab >= maximizers.size() || !maximizers[tab]) continue; QTextStream paramStream(¶mString); QString paramName; float paramValue; while(!paramStream.atEnd()) { paramStream >> paramName; paramStream >> paramValue; maximizers[tab]->LoadParams(paramName, paramValue); } QString algoName = maximizers[tab]->GetAlgoString(); fvec resultIt, resultVal, resultEval; FOR(f, folds) { maximizer = maximizers[tab]->GetMaximizer(); if(!maximizer) continue; maximizer->maxAge = optionsMaximize->iterationsSpin->value(); maximizer->stopValue = optionsMaximize->stoppingSpin->value(); Train(maximizer); Test(maximizer); resultIt.push_back(maximizer->age); resultVal.push_back(maximizer->MaximumValue()); resultEval.push_back(maximizer->Evaluations()); progress.setValue(f + i*folds); DEL(maximizer); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); if(progress.wasCanceled()) { compare->AddResults(resultEval, "Evaluations", algoName); compare->AddResults(resultVal, "Reward", algoName); compare->AddResults(resultIt, "Iterations", algoName); compare->Show(); return; } } compare->AddResults(resultEval, "Evaluations", algoName); compare->AddResults(resultVal, "Reward", algoName); compare->AddResults(resultIt, "Iterations", algoName); } if(line.startsWith("Classification")) { QStringList s = line.split(":"); int tab = s[1].toInt(); if(tab >= classifiers.size() || !classifiers[tab]) continue; QTextStream paramStream(¶mString); QString paramName; float paramValue; while(!paramStream.atEnd()) { paramStream >> paramName; paramStream >> paramValue; classifiers[tab]->LoadParams(paramName, paramValue); } QString algoName = classifiers[tab]->GetAlgoString(); fvec fmeasureTrain, fmeasureTest, errorTrain, errorTest, precisionTrain, precisionTest, recallTrain, recallTest; bvec trainList; if(optionsClassify->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } map classes; FOR(j, canvas->data->GetLabels().size()) classes[canvas->data->GetLabels()[j]]++; FOR(f, folds) { classifier = classifiers[tab]->GetClassifier(); if(!classifier) continue; Train(classifier, positive, trainRatio, trainList); bool bMulti = classifier->IsMultiClass() && DatasetManager::GetClassCount(canvas->data->GetLabels()); if(classifier->rocdata.size()>0) { if(!bMulti || classes.size() <= 2) { fvec res = GetBestFMeasure(classifier->rocdata[0]); fmeasureTrain.push_back(res[0]); precisionTrain.push_back(res[1]); recallTrain.push_back(res[2]); qDebug() << "training" << res[0] << res[1] << res[2]; } else { int errors = 0; std::vector rocdata = classifier->rocdata[0]; FOR(j, rocdata.size()) { qDebug() << "rocdata: " << j << rocdata[j].first << rocdata[j].second; if(rocdata[j].first != rocdata[j].second) { if(classes.size() > 2) errors++; else if((rocdata[j].first < 0) != rocdata[j].second) errors++; } } if(classes.size() <= 2) { float e = min(errors,(int)rocdata.size()-errors)/(float)rocdata.size(); fmeasureTrain.push_back(1-e); fmeasureTrain.push_back(1-e); } else { errorTrain.push_back(errors/(float)rocdata.size()); errorTest.push_back(errors/(float)rocdata.size()); } } } if(classifier->rocdata.size()>1) { if(!bMulti || classes.size() <= 2) { fvec res = GetBestFMeasure(classifier->rocdata[1]); fmeasureTest.push_back(res[0]); precisionTest.push_back(res[1]); recallTest.push_back(res[2]); } else { int errors = 0; std::vector rocdata = classifier->rocdata[1]; FOR(j, rocdata.size()) { if(rocdata[j].first != rocdata[j].second) { if(classes.size() > 2) errors++; else if((rocdata[j].first < 0) != rocdata[j].second) errors++; } } if(classes.size() <= 2) errorTest.push_back(min(errors,(int)rocdata.size()-errors)/(float)rocdata.size()); else errorTest.push_back(errors/(float)rocdata.size()); } } DEL(classifier); progress.setValue(f + i*folds); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); if(progress.wasCanceled()) { compare->AddResults(fmeasureTest, "F-Measure (Test)", algoName); compare->AddResults(errorTest, "Error (Test)", algoName); compare->AddResults(precisionTest, "Precision (Test)", algoName); compare->AddResults(recallTest, "Recall (Test)", algoName); compare->AddResults(fmeasureTrain, "F-Measure (Training)", algoName); compare->AddResults(errorTrain, "Error (Training)", algoName); compare->AddResults(precisionTrain, "Precision (Training)", algoName); compare->AddResults(recallTrain, "Recall (Training)", algoName); //compare->SetActiveResult(1); compare->Show(); return; } } compare->AddResults(fmeasureTest, "F-Measure (Test)", algoName); compare->AddResults(errorTest, "Error (Test)", algoName); compare->AddResults(precisionTest, "Precision (Test)", algoName); compare->AddResults(recallTest, "Recall (Test)", algoName); compare->AddResults(fmeasureTrain, "F-Measure (Training)", algoName); compare->AddResults(errorTrain, "Error (Training)", algoName); compare->AddResults(precisionTrain, "Precision (Training)", algoName); compare->AddResults(recallTrain, "Recall (Training)", algoName); //compare->SetActiveResult(1); } if(line.startsWith("Regression")) { QStringList s = line.split(":"); int tab = s[1].toInt(); if(tab >= regressors.size() || !regressors[tab]) continue; int outputDim = optionsCompare->outputDimCombo->currentIndex(); QTextStream paramStream(¶mString); QString paramName; float paramValue; while(!paramStream.atEnd()) { paramStream >> paramName; paramStream >> paramValue; regressors[tab]->LoadParams(paramName, paramValue); } bvec trainList; if(optionsRegress->manualTrainButton->isChecked()) { // we get the list of samples that are checked trainList = GetManualSelection(); } QString algoName = regressors[tab]->GetAlgoString(); fvec resultTrain, resultTest; FOR(f, folds) { regressor = regressors[tab]->GetRegressor(); if(!regressor) continue; qDebug() << " training: " << regressors[tab]->GetName(); Train(regressor, outputDim, trainRatio, trainList); if(regressor->trainErrors.size()) { float error = 0.f; FOR(i, regressor->trainErrors.size()) error += regressor->trainErrors[i]; error /= regressor->trainErrors.size(); resultTrain.push_back(error); } if(regressor->testErrors.size()) { float error = 0.f; FOR(i, regressor->testErrors.size()) error += regressor->testErrors[i]; error /= regressor->testErrors.size(); resultTest.push_back(error); } DEL(regressor); progress.setValue(f + i*folds); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); if(progress.wasCanceled()) { compare->AddResults(resultTest, "Error (Testing)", algoName); compare->AddResults(resultTrain, "Error (Training)", algoName); compare->Show(); return; } } compare->AddResults(resultTest, "Error (Testing)", algoName); compare->AddResults(resultTrain, "Error (Training)", algoName); } if(line.startsWith("Dynamical")) { QStringList s = line.split(":"); int tab = s[1].toInt(); if(tab >= dynamicals.size() || !dynamicals[tab]) continue; QTextStream paramStream(¶mString); QString paramName; float paramValue; while(!paramStream.atEnd()) { paramStream >> paramName; paramStream >> paramValue; dynamicals[tab]->LoadParams(paramName, paramValue); } QString algoName = dynamicals[tab]->GetAlgoString(); fvec resultReconst, resultTargetTraj, resultTarget; FOR(f, folds) { dynamical = dynamicals[tab]->GetDynamical(); if(!dynamical) continue; fvec results = Train(dynamical); if(results.size()) { resultReconst.push_back(results[0]); resultTargetTraj.push_back(results[1]); resultTarget.push_back(results[2]); } DEL(dynamical); progress.setValue(f + i*folds); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); if(progress.wasCanceled()) { compare->AddResults(resultReconst, "Reconstruction Error", algoName); compare->AddResults(resultTargetTraj, "Target Error (trajectories)", algoName); compare->AddResults(resultTarget, "Target Error (random points)", algoName); compare->Show(); return; } } compare->AddResults(resultReconst, "Reconstruction Error", algoName); compare->AddResults(resultTargetTraj, "Target Error (trajectories)", algoName); compare->AddResults(resultTarget, "Target Error (random points)", algoName); } compare->Show(); } } mldemos-0.4.3/MLDemos/optsClassify.ui000066400000000000000000000270131172143270300175030ustar00rootroot00000000000000 optionsClassifyWidget 0 0 635 193 0 0 Classification false 330 10 171 171 9 true 0 50 81 21 9 Train / Test ratio Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 90 50 61 21 9 Ratio between training and testing samples (100% means all samples are used for training) 7 10% 25% 33% 50% 66% 75% 90% 100% true 140 80 31 21 9 folds true 90 80 41 21 9 Number of cross-validation folds 1 20 5 90 20 41 21 9 0 255 1 0 20 81 21 9 Positive Class Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 30 140 110 32 9 Manual Selection true 30 110 110 32 9 Input Dimensions true 10 10 311 171 9 0 Algorithm true 330 90 80 21 9 Cross Validation Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 520 148 90 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Start the maximization process (uses starting position if one is available, or a random position otherwise)</span></p></body></html> Compare 520 10 90 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Classify the data using the current algorithm</span></p></body></html> Classify true 510 84 50 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Perform Cross-Validation and display results BoxPlot</span></p></body></html> C.Val 520 44 90 32 9 Clear the model information (does NOT clear the data) Clear true 570 84 50 21 9 Display Receiver-Operator-Characteristic (ROC) curve for the last training or cross-validation ROC mldemos-0.4.3/MLDemos/optsCluster.ui000066400000000000000000000214301172143270300173440ustar00rootroot00000000000000 optionsClusterWidget 0 0 635 193 0 0 Clustering false 500 10 124 182 9 9 Cluster the data using the current parameters Cluster 9 Compute the optimial number of clusters according to different metrics Optimize Clusters 9 One iteration 9 Qt::Vertical 20 40 9 Manual Selection true 9 Clear 10 10 300 171 9 0 Kernel 320 20 101 60 10 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cluster quality metrics:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- RSS: Residual Sum of Squares</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- BIC: Bayesian Information Criterion</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- AIC: Akaike Information Criterion</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- F1: F-Measure </p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For all metrics except F-Measure, the lower value is the best</p></body></html> 430 83 60 20 9 Percentage of labels that are provided to the system for computing clustering quality. The indicated percentage of labels is provided for each class (this ensures that a minimum amount of samples are provided when classes are very unbalanced) 7 1% 5% 10% 20% 33% 50% 75% 100% 320 83 110 20 9 Class labels for training 320 110 170 70 10 430 40 60 20 9 Metric to use to determine the optimal number of clusters (Cluster Count button on the right) 0 RSS BIC AIC F1 430 20 60 20 9 Optimize by mldemos-0.4.3/MLDemos/optsCompare.ui000066400000000000000000000275121172143270300173200ustar00rootroot00000000000000 optionsCompare 0 0 666 277 0 0 Compare Algorithms false 0 0 0 0 0 300 130 9 true 0 70 81 21 9 Train / Test ratio Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 90 70 61 21 9 Ratio between training and testing samples (100% means all samples are used for training) 4 10% 25% 33% 50% 66% 75% 90% 100% true 140 100 31 21 9 folds true 90 100 41 21 9 Number of cross-validation folds 1 9999 10 true 0 100 80 21 9 Cross Validation Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 180 90 61 32 9 Clear the model information (does NOT clear the data) Remove 190 1 105 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Classify the data using the current algorithm</span></p></body></html> Compare true 200 35 90 32 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Perform Cross-Validation and display results BoxPlot</span></p></body></html> to Clipboard 240 90 61 32 9 Clear the model information (does NOT clear the data) Clear All 100 10 80 21 9 Regression Dim Qt::AlignCenter 0 20 100 32 9 Input Dims false true 100 30 80 21 9 Ratio between training and testing samples (100% means all samples are used for training) 1 1 2 QAbstractItemView::SingleSelection mldemos-0.4.3/MLDemos/optsDynamic.ui000066400000000000000000000372521172143270300173200ustar00rootroot00000000000000 optionsDynamicWidget 0 0 635 193 0 0 Dynamical Systems false 10 10 331 171 9 0 Kernels 349 10 171 171 9 10 20 51 21 9 Centered true 50 20 60 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Ratio between training and testing samples</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(100% means all samples are used for training)</span></p></body></html> 0 None End Start 10 50 40 21 9 Samples true 50 50 50 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Number of cross-validation folds</span></p></body></html> 10 1000 10 100 true 100 50 70 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Ratio between training and testing samples</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(100% means all samples are used for training)</span></p></body></html> 1 None Uniform 40 0 91 21 9 Pre-Processing Qt::AlignCenter 120 20 50 21 9 zero true 30 80 20 21 9 dT true 50 80 50 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Number of cross-validation folds</span></p></body></html> 3 0.001000000000000 10.000000000000000 0.010000000000000 0.020000000000000 true 50 140 80 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Ratio between training and testing samples</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(100% means all samples are used for training)</span></p></body></html> 0 None 40 120 100 21 9 Obstacle Avoidance Qt::AlignCenter 110 80 50 21 9 color false 530 10 90 171 9 9 Compute regression on data using the current algorithm Train 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Clear the model information</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(does NOT clear the data)</span></p></body></html> Clear 9 Qt::Vertical 20 40 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Start the maximization process (uses starting position if one is available, or a random position otherwise)</span></p></body></html> Compare mldemos-0.4.3/MLDemos/optsMaximize.ui000066400000000000000000000342621172143270300175150ustar00rootroot00000000000000 optionsMaximizeWidget 0 0 620 193 0 0 Optimization false 400 20 31 31 30 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:30pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Starting Position</p></body></html> ¤ false 10 10 311 171 9 0 Algorithm 500 10 110 171 9 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Start the maximization process (uses starting position if one is available, or a random position otherwise)</span></p></body></html> Maximize 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Stops / Resumes maximization process. Will not influence mthods that have converged already.</span></p></body></html> Stop/Start 9 Clear the model information (does NOT clear the data) Clear 9 Qt::Vertical 20 40 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Start the maximization process (uses starting position if one is available, or a random position otherwise)</span></p></body></html> Compare 360 60 31 31 Lucida Console 32 50 false false false false true false 350 90 50 20 9 Gaussian Qt::AlignCenter 400 70 40 20 8 0.010000000000000 1.000000000000000 0.050000000000000 0.200000000000000 440 90 50 20 9 Gradient Qt::AlignCenter 450 60 31 31 Lucida Console 32 50 false false false false true false 400 55 30 20 9 Var Qt::AlignCenter 360 160 50 20 8 1 9999 200 350 140 70 20 9 Max Iterations Qt::AlignCenter 440 160 50 20 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stopping Criterion: stop maximization if maximum gets above this value</p></body></html> 0.010000000000000 1.000000000000000 0.010000000000000 0.980000000000000 430 140 60 20 9 Stop Crit. Qt::AlignCenter 350 110 90 26 9 Griewangk Rastragin Schwefel Ackley Six-Humps 440 110 51 26 9 Set label_4 targetButton tabWidget layoutWidget gaussianButton label_2 varianceSpin label_3 gradientButton iterationsSpin label_5 stoppingSpin label_6 benchmarkCombo benchmarkButton mldemos-0.4.3/MLDemos/optsProject.ui000066400000000000000000000057701172143270300173420ustar00rootroot00000000000000 optionsProjectWidget 0 0 635 193 0 0 Classification false 10 10 381 171 9 0 Algorithm 520 10 90 32 9 Project the current source data onto the Project 520 44 90 32 9 Restore source data (erases projection) Revert 520 80 90 32 9 Reproject already projected data ReProject 410 120 110 32 9 Manual Selection true mldemos-0.4.3/MLDemos/optsRegress.ui000066400000000000000000000303071172143270300173400ustar00rootroot00000000000000 optionsRegressWidget 0 0 635 193 0 0 Regression false 10 10 311 171 9 0 Kernel 330 10 180 171 9 10 50 81 21 9 Train / Test ratio true 100 50 61 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Ratio between training and testing samples</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(100% means all samples are used for training)</span></p></body></html> 7 10% 25% 33% 50% 66% 75% 90% 100% 150 80 31 21 9 folds true 100 80 41 21 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Number of cross-validation folds</span></p></body></html> 1 20 5 40 140 110 32 9 Manual Selection true 40 0 110 21 9 Regression Dimension 40 110 110 32 9 Input Dimensions false true 40 20 100 21 9 Ratio between training and testing samples (100% means all samples are used for training) 1 1 2 true 340 90 80 21 9 Cross Validation 520 10 100 173 9 9 Compute regression on data using the current algorithm Regress 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Clear the model information</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(does NOT clear the data)</span></p></body></html> Clear true 9 Perform Cross-Validation and display results BoxPlot Cross Valid 9 Qt::Vertical 20 40 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Lucida Grande'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Start the maximization process (uses starting position if one is available, or a random position otherwise)</span></p></body></html> Compare mldemos-0.4.3/MLDemos/statisticsDialog.ui000066400000000000000000000166721172143270300203430ustar00rootroot00000000000000 statisticsDialog 0 0 558 395 0 0 Information and Statistics 1 Algorithm Information false true true true Statistics QFrame::NoFrame QFrame::Sunken true 0 0 318 316 0 0 0 0 0 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 1 1 160 320 Training Curves 1 1 480 320 0 0 Cross-Validation 0 2 0 1 1 240 320 0 0 1 1 240 300 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true mldemos-0.4.3/MLDemos/viewOptions.ui000066400000000000000000000125271172143270300173520ustar00rootroot00000000000000 viewOptionDialog true 0 0 230 120 0 0 230 120 230 120 MS Shell Dlg 2 8 Display Options 10 30 90 17 Lucida Grande Learned Model true 10 70 90 17 Lucida Grande Density Map true 10 50 90 17 Lucida Grande Model Info true 10 10 90 17 Lucida Grande Samples true 120 10 90 20 Lucida Grande 9 Copy current canvas image to clipboard to Clipboard 130 80 50 20 Lucida Grande 1 -20.000000000000000 20.000000000000000 0.500000000000000 0.000000000000000 85 80 40 20 Lucida Grande 8 Zoom Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 180 80 40 20 Lucida Grande 9 Adjust zoom to fit all current data Fit 10 90 50 17 Lucida Grande Grid true mldemos-0.4.3/MLDemos_full.pro000066400000000000000000000030011172143270300162140ustar00rootroot00000000000000############################## # # # MLDemos Bundle # # # ############################## TEMPLATE = subdirs # the main software CONFIG += ordered SUBDIRS = Core 3rdParty MLDemos Core.file = Core/Core.pro 3rdParty.file = _3rdParty/3rdParty.pro MLDemos.file = MLDemos/MLDemos.pro MLDemos.depends = Core # algorithm plugins ALGOPATH = _AlgorithmsPlugins #SUBDIRS += Kernel Projections SUBDIRS += Obstacle GMM Kernel KNN Projections LWPR Maximizers OpenCV SEDS # SUBDIRS += HMM GMM.file = $$ALGOPATH/GMM/pluginGMM.pro Kernel.file = $$ALGOPATH/KernelMethods/pluginKernel.pro KNN.file = $$ALGOPATH/KNN/pluginKNN.pro Projections.file = $$ALGOPATH/Projections/pluginProjections.pro LWPR.file = $$ALGOPATH/LWPR/pluginLWPR.pro Obstacle.file = $$ALGOPATH/Obstacle/pluginAvoidance.pro SEDS.file = $$ALGOPATH/SEDS/pluginSEDS.pro Maximizers.file = $$ALGOPATH/Maximizers/pluginMaximizers.pro OpenCV.file = $$ALGOPATH/OpenCV/pluginOpenCV.pro MLR.file = $$ALGOPATH/MLR/pluginMLR.pro XMeans.file = $$ALGOPATH/XMeans/pluginXMeans.pro HMM.file = $$ALGOPATH/HMM/pluginHMM.pro # input plugins INPUTPATH = _IOPlugins SUBDIRS += PCAFaces #SUBDIRS += ImportTimeseries PCAFaces.file = $$INPUTPATH/PCAFaces/pluginPCAFaces.pro RandomEmitter.file = $$INPUTPATH/RandomEmitter/pluginRandomEmitter.pro WebImport.file = $$INPUTPATH/WebImport/pluginWebImport.pro CSVImport.file = $$INPUTPATH/CSVImport/pluginCSVImport.pro ImportTimeseries.file = $$INPUTPATH/ImportTimeseries/pluginImportTimeseries.pro mldemos-0.4.3/MLDemos_variables.pri000066400000000000000000000074721172143270300172340ustar00rootroot00000000000000############################## # # # MLDemos Variables # # # ############################## # PLEASE EDIT THIS PART TO FIT YOUR NEEDS/SETUP win32{ MLBUILD = C:/tmp/MLDemos/$$NAME CONFIG += WIN32 }else{ MLBUILD = /tmp/MLDemos/$$NAME } # choices are opencv22 or opencv21 CONFIG += opencv22 CONFIG(opencv22)|CONFIG(opencv21){ message("You have selected to use the OpenCV library, if you do not have/desire it, please modify MLDemos_variables.pri") } CONFIG(boost){ message("You have selected to use the Boost headers library, if you do not have/desire it, please modify MLDemos_variables.pri") DEFINES += WITHBOOST } ############################################ # PATHS for the BOOST and OPENCV libraries # ############################################ macx|unix{ CONFIG(boost):BOOST = /usr/local/boost_1_47_0 }else{ CONFIG(boost):BOOST = E:/DEV/boost_1_47_0 } # opencv includes win32:CONFIG(opencv22){ message("please adjust the include and lib paths to fit your system") INCLUDEPATH += . "C:/DEV/OpenCV2.3-GCC/include/" LIBS += -L"C:/DEV/OpenCV2.3-GCC/lib/" # "C:/OpenCV2.2/include/" #LIBS += -L"C:/OpenCV2.2/lib/" LIBS += -lopencv_core230 \ -lopencv_features2d230 \ -lopencv_highgui230 \ -lopencv_imgproc230 \ -lopencv_legacy230 \ -lopencv_ml230 } else:CONFIG(opencv22) { INCLUDEPATH += /usr/local/include/ LIBS += -L/usr/local/lib DEFINES += OPENCV22 message("using opencv22 or later") LIBS += \ -lopencv_core \ -lopencv_features2d \ -lopencv_highgui \ -lopencv_imgproc \ -lopencv_legacy \ -lopencv_ml } else:CONFIG(opencv21) { INCLUDEPATH += /usr/local/include/ LIBS += -L/usr/local/lib DEFINES += OPENCV21 message("using opencv21") LIBS += \ -lcv \ -lcxcore \ -lcvaux \ -lml \ -lhighgui } # PLEASE EDIT UNTIL HERE TO FIT YOUR NEEDS/SETUP mainApp|coreLib{ }else{ TARGET = $$qtLibraryTarget($$NAME) CONFIG(debug, debug|release):DESTDIR = "$$MLPATH/pluginsDebug" CONFIG(release, debug|release):DESTDIR = "$$MLPATH/plugins" } CONFIG(debug, debug|release){ DEFINES += DEBUG message("debug mode") }else{ message("release mode") } macx:DEFINES += MACX win32:DEFINES += WIN32 win32{ CONFIG(Debug, Debug|Release){ MOC_DIR = $${MLBUILD}/Debug UI_DIR = $${MLBUILD}/Debug RCC_DIR = $${MLBUILD}/Debug OBJECTS_DIR = $${MLBUILD}/Debug }else{ MOC_DIR = $${MLBUILD}/Release UI_DIR = $${MLBUILD}/Release RCC_DIR = $${MLBUILD}/Release OBJECTS_DIR = $${MLBUILD}/Release } }else{ MOC_DIR = $${MLBUILD}/build UI_DIR = $${MLBUILD}/build RCC_DIR = $${MLBUILD}/build OBJECTS_DIR = $${MLBUILD}/build } DEPENDPATH += . \ .. \ $${MLPATH}/Core \ $${MLPATH}/_3rdParty INCLUDEPATH += . \ $${MLPATH}/Core \ $${MLPATH}/MLDemos \ $${MLPATH}/_3rdParty unix{ INCLUDEPATH += /usr/include/qt4 \ /usr/include/qt4/QtCore \ /usr/include/qt4/QtGui \ /usr/include/qt4/QtSvg \ /usr/include/qt4/QtOpenGL LIBS += -L/usr/local/lib } CONFIG(coreLib){ }else{ LIBS += -L$$MLPATH/Core -lCore } LIBS += -L$$MLPATH/_3rdParty -l3rdParty ################################ # Turn the bloody warnings off # ################################ macx|unix { QMAKE_CXXFLAGS_WARN_ON = "" QMAKE_CXXFLAGS += -Wno-all QMAKE_CXXFLAGS += -Wno-endif-labels QMAKE_CXXFLAGS += -Wno-unused-variable QMAKE_CXXFLAGS += -Wno-unused-parameter QMAKE_CXXFLAGS += -Wno-switch QMAKE_CXXFLAGS += -Wtrigraphs QMAKE_CXXFLAGS += -Wreturn-type #QMAKE_CXXFLAGS += -Wnon-virtual-dtor QMAKE_CXXFLAGS += -Woverloaded-virtual #QMAKE_CXXFLAGS += -Wunused-variable #QMAKE_CXXFLAGS += -Wunused-value QMAKE_CXXFLAGS += -Wunknown-pragmas QMAKE_CXXFLAGS += -Wno-shadow QMAKE_CXXFLAGS += -Wno-deprecated-declarations QMAKE_CXXFLAGS += -Wno-missing-braces } mldemos-0.4.3/_3rdParty/000077500000000000000000000000001172143270300150255ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/3rdParty.pro000066400000000000000000000205321172143270300172610ustar00rootroot00000000000000########################### # Configuration # ########################### TEMPLATE = lib NAME = 3rdParty MLPATH =.. CONFIG += mainApp static include($$MLPATH/MLDemos_variables.pri) win32{ DESTDIR = ../_3rdParty } ########################### # Files # ########################### HEADERS += \ fgmm/em.h \ fgmm/fgmm++.hpp \ fgmm/fgmm.h \ fgmm/gaussian.h \ fgmm/regression.h \ fgmm/smat.h SOURCES += \ fgmm/em.cpp \ fgmm/gaussian.cpp \ fgmm/gmm.cpp \ fgmm/gmmregression.cpp \ fgmm/smat.cpp \ fgmm/update.cpp HEADERS += \ MathLib/Differentiator.h \ MathLib/GradientDescent.h \ MathLib/IKGroupSolver.h \ MathLib/IKSubSolver.h \ MathLib/Macros.h \ MathLib/MathLib.h \ MathLib/MathLibCommon.h \ MathLib/Matrix.h \ MathLib/Matrix3.h \ MathLib/Matrix4.h \ MathLib/ReferenceFrame.h \ MathLib/Regression.h \ MathLib/SpatialForce.h \ MathLib/SpatialFrame.h \ MathLib/SpatialInertia.h \ MathLib/SpatialMatrix.h \ MathLib/SpatialVector.h \ MathLib/SpatialVelocity.h \ MathLib/TMatrix.h \ MathLib/TVector.h \ MathLib/Vector.h \ MathLib/Vector3.h SOURCES += \ MathLib/Differentiator.cpp \ MathLib/GradientDescent.cpp \ MathLib/IKGroupSolver.cpp \ MathLib/IKSubSolver.cpp \ MathLib/Macros.cpp \ MathLib/MathLib.cpp \ MathLib/MathLibCommon.cpp \ MathLib/Matrix.cpp \ MathLib/Matrix3.cpp \ MathLib/Matrix4.cpp \ MathLib/ReferenceFrame.cpp \ MathLib/Regression.cpp \ MathLib/SpatialForce.cpp \ MathLib/SpatialFrame.cpp \ MathLib/SpatialInertia.cpp \ MathLib/SpatialMatrix.cpp \ MathLib/SpatialVector.cpp \ MathLib/SpatialVelocity.cpp \ MathLib/TMatrix.cpp \ MathLib/TVector.cpp \ MathLib/Vector.cpp \ MathLib/Vector3.cpp HEADERS += \ PSO/pso.h \ PSO/memoryAllocation.h \ PSO/optimizer.h SOURCES += \ PSO/pso.cpp \ PSO/memoryAllocation.cpp \ PSO/optimizer.cpp HEADERS += \ newmat11/controlw.h \ newmat11/include.h \ newmat11/myexcept.h \ newmat11/newmat.h \ newmat11/newmatap.h \ newmat11/newmatio.h \ newmat11/newmatnl.h \ newmat11/newmatrc.h \ newmat11/newmatrm.h \ newmat11/precisio.h \ newmat11/solution.h SOURCES += \ newmat11/bandmat.cpp \ newmat11/cholesky.cpp \ newmat11/evalue.cpp \ newmat11/fft.cpp \ newmat11/hholder.cpp \ newmat11/jacobi.cpp \ newmat11/myexcept.cpp \ newmat11/newfft.cpp \ newmat11/newmat1.cpp \ newmat11/newmat2.cpp \ newmat11/newmat3.cpp \ newmat11/newmat4.cpp \ newmat11/newmat5.cpp \ newmat11/newmat6.cpp \ newmat11/newmat7.cpp \ newmat11/newmat8.cpp \ newmat11/newmat9.cpp \ newmat11/newmatex.cpp \ newmat11/newmatnl.cpp \ newmat11/newmatrm.cpp \ newmat11/nm_misc.cpp \ newmat11/solution.cpp \ newmat11/sort.cpp \ newmat11/submat.cpp \ newmat11/svd.cpp HEADERS += \ lwpr/lwpr.h \ lwpr/lwpr.hh \ lwpr/lwpr_aux.h \ lwpr/lwpr_binio.h \ lwpr/lwpr_config.h \ lwpr/lwpr_config_def.h \ lwpr/lwpr_math.h \ lwpr/lwpr_mem.h \ lwpr/lwpr_xml.h SOURCES += \ lwpr/lwpr.c \ lwpr/lwpr_aux.c \ lwpr/lwpr_binio.c \ lwpr/lwpr_math.c \ lwpr/lwpr_mem.c \ lwpr/lwpr_xml.c HEADERS += JnS/Matutil.h \ JnS/JnS.h SOURCES += JnS/Matutil.cpp \ JnS/JnS.cpp HEADERS += liblinear/linear.h \ liblinear/tron.h \ liblinear/blasp.h \ liblinear/blas.h SOURCES += liblinear/linear.cpp \ liblinear/tron.cpp \ liblinear/daxpy.c \ liblinear/ddot.c \ liblinear/dnrm2.c \ liblinear/dscal.c HEADERS += ANN/ANN.h \ ANN/ANNperf.h \ ANN/ANNx.h \ ANN/bd_tree.h \ ANN/kd_fix_rad_search.h \ ANN/kd_pr_search.h \ ANN/kd_search.h \ ANN/kd_split.h \ ANN/kd_tree.h \ ANN/kd_util.h \ ANN/pr_queue.h \ ANN/pr_queue_k.h SOURCES += ANN/ANN.cpp \ ANN/bd_fix_rad_search.cpp \ ANN/bd_pr_search.cpp \ ANN/bd_search.cpp \ ANN/bd_tree.cpp \ ANN/brute.cpp \ ANN/kd_dump.cpp \ ANN/kd_fix_rad_search.cpp \ ANN/kd_pr_search.cpp \ ANN/kd_search.cpp \ ANN/kd_split.cpp \ ANN/kd_tree.cpp \ ANN/kd_util.cpp \ ANN/perf.cpp HEADERS += \ dlib/algs.h \ dlib/array.h \ dlib/array2d.h \ dlib/assert.h \ dlib/base64.h \ dlib/bayes_utils.h \ dlib/bigint.h \ dlib/binary_search_tree.h \ dlib/bit_stream.h \ dlib/bound_function_pointer.h \ dlib/byte_orderer.h \ dlib/cmd_line_parser.h \ dlib/compress_stream.h \ dlib/conditioning_class.h \ dlib/config_reader.h \ dlib/cpp_pretty_printer.h \ dlib/cpp_tokenizer.h \ dlib/crc32.h \ dlib/data_io.h \ dlib/dir_nav.h \ dlib/directed_graph.h \ dlib/enable_if.h \ dlib/entropy_decoder.h \ dlib/entropy_decoder_model.h \ dlib/entropy_encoder.h \ dlib/entropy_encoder_model.h \ dlib/error.h \ dlib/geometry.h \ dlib/graph.h \ dlib/graph_utils.h \ dlib/gui_core.h \ dlib/gui_widgets.h \ dlib/hash_map.h \ dlib/hash_set.h \ dlib/hash_table.h \ dlib/image_io.h \ dlib/image_keypoint.h \ dlib/image_transforms.h \ dlib/is_kind.h \ dlib/linker.h \ dlib/logger.h \ dlib/lz77_buffer.h \ dlib/lzp_buffer.h \ dlib/manifold_regularization.h \ dlib/map.h \ dlib/matrix.h \ dlib/md5.h \ dlib/member_function_pointer.h \ dlib/memory_manager.h \ dlib/memory_manager_global.h \ dlib/memory_manager_stateless.h \ dlib/misc_api.h \ dlib/mlp.h \ dlib/noncopyable.h \ dlib/opencv.h \ dlib/optimization.h \ dlib/pipe.h \ dlib/pixel.h \ dlib/platform.h \ dlib/quantum_computing.h \ dlib/queue.h \ dlib/rand.h \ dlib/ref.h \ dlib/reference_counter.h \ dlib/revision.h \ dlib/sequence.h \ dlib/serialize.h \ dlib/server.h \ dlib/set.h \ dlib/set_utils.h \ dlib/sliding_buffer.h \ dlib/smart_pointers.h \ dlib/smart_pointers_thread_safe.h \ dlib/sockets.h \ dlib/sockstreambuf.h \ dlib/sort.h \ dlib/stack.h \ dlib/stack_trace.h \ dlib/static_map.h \ dlib/static_set.h \ dlib/statistics.h \ dlib/std_allocator.h \ dlib/stl_checked.h \ dlib/string.h \ dlib/svm.h \ dlib/svm_threaded.h \ dlib/sync_extension.h \ dlib/threads.h \ dlib/time_this.h \ dlib/timeout.h \ dlib/timer.h \ dlib/tokenizer.h \ dlib/tuple.h \ dlib/type_safe_union.h \ dlib/uintn.h \ dlib/unicode.h \ dlib/windows_magic.h \ dlib/xml_parser.h \ HEADERS += \ nlopt.hpp \ nlopt/tools.h \ nlopt/stogo_config.h \ nlopt/stogo.h \ nlopt/soboldata.h \ nlopt/slsqp.h \ nlopt/redblack.h \ nlopt/praxis.h \ nlopt/nlopt-util.h \ nlopt/nlopt-internal.h \ nlopt/nlopt-in.hpp \ nlopt/nlopt_optimize_usage.h \ nlopt/nlopt.hpp \ nlopt/nlopt.h \ nlopt/newuoa.h \ nlopt/neldermead.h \ nlopt/mma.h \ nlopt/mlsl.h \ nlopt/luksan.h \ nlopt/local.h \ nlopt/linalg.h \ nlopt/isres.h \ nlopt/global.h \ nlopt/f77funcs_.h \ nlopt/f77funcs.h \ nlopt/direct-internal.h \ nlopt/direct.h \ nlopt/crs.h \ nlopt/cobyla.h \ nlopt/cdirect.h \ nlopt/bobyqa.h \ nlopt/auglag.h \ nlopt/config.h SOURCES += \ nlopt/tools.cc \ nlopt/timer.c \ nlopt/stop.c \ nlopt/stogo.cc \ nlopt/sobolseq.c \ nlopt/slsqp.c \ nlopt/sbplx.c \ nlopt/rescale.c \ nlopt/redblack.c \ nlopt/qsort_r.c \ nlopt/pssubs.c \ nlopt/praxis.c \ nlopt/pnet.c \ nlopt/plis.c \ nlopt/plip.c \ nlopt/options.c \ nlopt/optimize.c \ nlopt/nldrmd.c \ nlopt/newuoa.c \ nlopt/mt19937ar.c \ nlopt/mssubs.c \ nlopt/mma.c \ nlopt/mlsl.c \ nlopt/local.cc \ nlopt/linalg.cc \ nlopt/isres.c \ nlopt/hybrid.c \ nlopt/global.cc \ nlopt/general.c \ nlopt/f77api.c \ nlopt/DIRsubrout.c \ nlopt/DIRserial.c \ nlopt/direct_wrap.c \ nlopt/DIRect.c \ nlopt/deprecated.c \ nlopt/crs.c \ nlopt/cobyla.c \ nlopt/cdirect.c \ nlopt/bobyqa.c \ nlopt/auglag.c HEADERS += \ LAMP_HMM/discreteObsProb.h \ LAMP_HMM/explicitDurationTrans.h \ LAMP_HMM/gammaProb.h \ LAMP_HMM/gaussianObsProb.h \ LAMP_HMM/hmm.h \ LAMP_HMM/initStateProb.h \ LAMP_HMM/obs.h \ LAMP_HMM/obsProb.h \ LAMP_HMM/obsSeq.h \ LAMP_HMM/plainStateTrans.h \ LAMP_HMM/stateTrans.h \ LAMP_HMM/utils.h \ LAMP_HMM/vectorObsProb.h SOURCES += \ LAMP_HMM/checkDurationDist.cpp \ LAMP_HMM/discreteObsProb.cpp \ LAMP_HMM/explicitDurationTrans.cpp \ LAMP_HMM/gammaProb.cpp \ LAMP_HMM/gaussianObsProb.cpp \ LAMP_HMM/hmm.cpp \ LAMP_HMM/hmmFind.cpp \ LAMP_HMM/initStateProb.cpp \ LAMP_HMM/obsSeq.cpp \ LAMP_HMM/plainStateTrans.cpp \ LAMP_HMM/readConfigFile.cpp \ LAMP_HMM/utils.cpp \ LAMP_HMM/vectorObsProb.cpp #unix{ # BOOST = /usr/local/boost_1_47_0 #}else{ # BOOST = E:/DEV/boost_1_47_0 #} #INCLUDEPATH += $$BOOST #HEADERS += \ # HMMlib/allocator_traits.hpp \ # HMMlib/float_traits.hpp \ # HMMlib/hmm_matrix.hpp \ # HMMlib/hmm_table.hpp \ # HMMlib/hmm_vector.hpp \ # HMMlib/hmm.hpp \ # HMMlib/operator_traits.hpp \ # HMMlib/sse_operator_traits.hpp #SOURCES += \ # HMMlib/hmm_matrix_test.cpp \ # HMMlib/hmm_test.cpp \ # HMMlib/hmm_vector_test.cpp mldemos-0.4.3/_3rdParty/ANN/000077500000000000000000000000001172143270300154415ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/ANN/ANN.cpp000066400000000000000000000157151172143270300165720ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: ANN.cpp // Programmer: Sunil Arya and David Mount // Description: Methods for ANN.h and ANNx.h // Last modified: 01/27/10 (Version 1.1.2) //---------------------------------------------------------------------- // Copyright (c) 1997-2010 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Added performance counting to annDist() // Revision 1.1.2 01/27/10 // Fixed minor compilation bugs for new versions of gcc //---------------------------------------------------------------------- #include // C standard lib defs #include // all ANN includes #include // ANN performance using namespace std; // make std:: accessible ANN_METRIC ANN::MetricType = ANN_METRIC0; double ANN::MetricPower = 3.; //---------------------------------------------------------------------- // Point methods //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Distance utility. // (Note: In the nearest neighbor search, most distances are // computed using partial distance calculations, not this // procedure.) //---------------------------------------------------------------------- ANNdist annDist( // interpoint squared distance int dim, ANNpoint p, ANNpoint q) { register int d; register ANNcoord diff; register ANNcoord dist; dist = 0; for (d = 0; d < dim; d++) { diff = p[d] - q[d]; switch(ANN::MetricType) { case ANN_METRIC0: dist = ANN_SUM0(dist, ANN_POW0(diff)); break; case ANN_METRIC1: dist = ANN_SUM1(dist, ANN_POW1(diff)); break; case ANN_METRIC2: dist = ANN_SUM(dist, ANN_POWp(diff)); break; case ANN_METRICP: dist = ANN_SUMp(dist, ANN_POWp(diff)); break; } } ANN_FLOP(3*dim) // performance counts ANN_PTS(1) ANN_COORD(dim) return dist; } //---------------------------------------------------------------------- // annPrintPoint() prints a point to a given output stream. //---------------------------------------------------------------------- void annPrintPt( // print a point ANNpoint pt, // the point int dim, // the dimension std::ostream &out) // output stream { for (int j = 0; j < dim; j++) { out << pt[j]; if (j < dim-1) out << " "; } } //---------------------------------------------------------------------- // Point allocation/deallocation: // // Because points (somewhat like strings in C) are stored // as pointers. Consequently, creating and destroying // copies of points may require storage allocation. These // procedures do this. // // annAllocPt() and annDeallocPt() allocate a deallocate // storage for a single point, and return a pointer to it. // // annAllocPts() allocates an array of points as well a place // to store their coordinates, and initializes the points to // point to their respective coordinates. It allocates point // storage in a contiguous block large enough to store all the // points. It performs no initialization. // // annDeallocPts() should only be used on point arrays allocated // by annAllocPts since it assumes that points are allocated in // a block. // // annCopyPt() copies a point taking care to allocate storage // for the new point. // // annAssignRect() assigns the coordinates of one rectangle to // another. The two rectangles must have the same dimension // (and it is not possible to test this here). //---------------------------------------------------------------------- ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point { ANNpoint p = new ANNcoord[dim]; for (int i = 0; i < dim; i++) p[i] = c; return p; } ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim { ANNpointArray pa = new ANNpoint[n]; // allocate points ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords for (int i = 0; i < n; i++) { pa[i] = &(p[i*dim]); } return pa; } void annDeallocPt(ANNpoint &p) // deallocate 1 point { delete [] p; p = NULL; } void annDeallocPts(ANNpointArray &pa) // deallocate points { delete [] pa[0]; // dealloc coordinate storage delete [] pa; // dealloc points pa = NULL; } ANNpoint annCopyPt(int dim, ANNpoint source) // copy point { ANNpoint p = new ANNcoord[dim]; for (int i = 0; i < dim; i++) p[i] = source[i]; return p; } // assign one rect to another void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source) { for (int i = 0; i < dim; i++) { dest.lo[i] = source.lo[i]; dest.hi[i] = source.hi[i]; } } // is point inside rectangle? ANNbool ANNorthRect::inside(int dim, ANNpoint p) { for (int i = 0; i < dim; i++) { if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse; } return ANNtrue; } //---------------------------------------------------------------------- // Error handler //---------------------------------------------------------------------- void annError(const char* msg, ANNerr level) { if (level == ANNabort) { cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n"; exit(1); } else { cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n"; } } //---------------------------------------------------------------------- // Limit on number of points visited // We have an option for terminating the search early if the // number of points visited exceeds some threshold. If the // threshold is 0 (its default) this means there is no limit // and the algorithm applies its normal termination condition. // This is for applications where there are real time constraints // on the running time of the algorithm. //---------------------------------------------------------------------- int ANNmaxPtsVisited = 0; // maximum number of pts visited int ANNptsVisited; // number of pts visited in search //---------------------------------------------------------------------- // Global function declarations //---------------------------------------------------------------------- void annMaxPtsVisit( // set limit on max. pts to visit in search int maxPts) // the limit { ANNmaxPtsVisited = maxPts; } mldemos-0.4.3/_3rdParty/ANN/ANN.h000066400000000000000000001064521172143270300162360ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: ANN.h // Programmer: Sunil Arya and David Mount, // multiple-metrics modifications by Basilio Noris // Description: Basic include file for approximate nearest // neighbor searching. // Last modified: 01/27/10 (Version 1.1.2) //---------------------------------------------------------------------- // Copyright (c) 1997-2010 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Added copyright and revision information // Added ANNcoordPrec for coordinate precision. // Added methods theDim, nPoints, maxPoints, thePoints to ANNpointSet. // Cleaned up C++ structure for modern compilers // Revision 1.1 05/03/05 // Added fixed-radius k-NN searching // Revision 1.1.2 01/27/10 // Fixed minor compilation bugs for new versions of gcc //---------------------------------------------------------------------- //---------------------------------------------------------------------- // ANN - approximate nearest neighbor searching // ANN is a library for approximate nearest neighbor searching, // based on the use of standard and priority search in kd-trees // and balanced box-decomposition (bbd) trees. Here are some // references to the main algorithmic techniques used here: // // kd-trees: // Friedman, Bentley, and Finkel, ``An algorithm for finding // best matches in logarithmic expected time,'' ACM // Transactions on Mathematical Software, 3(3):209-226, 1977. // // Priority search in kd-trees: // Arya and Mount, ``Algorithms for fast vector quantization,'' // Proc. of DCC '93: Data Compression Conference, eds. J. A. // Storer and M. Cohn, IEEE Press, 1993, 381-390. // // Approximate nearest neighbor search and bbd-trees: // Arya, Mount, Netanyahu, Silverman, and Wu, ``An optimal // algorithm for approximate nearest neighbor searching,'' // 5th Ann. ACM-SIAM Symposium on Discrete Algorithms, // 1994, 573-582. //---------------------------------------------------------------------- #ifndef ANN_H #define ANN_H /* #ifdef WIN32 //---------------------------------------------------------------------- // For Microsoft Visual C++, externally accessible symbols must be // explicitly indicated with DLL_API, which is somewhat like "extern." // // The following ifdef block is the standard way of creating macros // which make exporting from a DLL simpler. All files within this DLL // are compiled with the DLL_EXPORTS preprocessor symbol defined on the // command line. In contrast, projects that use (or import) the DLL // objects do not define the DLL_EXPORTS symbol. This way any other // project whose source files include this file see DLL_API functions as // being imported from a DLL, wheras this DLL sees symbols defined with // this macro as being exported. //---------------------------------------------------------------------- #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif //---------------------------------------------------------------------- // DLL_API is ignored for all other systems //---------------------------------------------------------------------- #else #define DLL_API #endif */ #define DLL_API //---------------------------------------------------------------------- // basic includes //---------------------------------------------------------------------- #include // standard lib includes #include // math includes #include // I/O streams #include // C-style strings //---------------------------------------------------------------------- // Limits // There are a number of places where we use the maximum double value as // default initializers (and others may be used, depending on the // data/distance representation). These can usually be found in limits.h // (as LONG_MAX, INT_MAX) or in float.h (as DBL_MAX, FLT_MAX). // // Not all systems have these files. If you are using such a system, // you should set the preprocessor symbol ANN_NO_LIMITS_H when // compiling, and modify the statements below to generate the // appropriate value. For practical purposes, this does not need to be // the maximum double value. It is sufficient that it be at least as // large than the maximum squared distance between between any two // points. //---------------------------------------------------------------------- #ifdef ANN_NO_LIMITS_H // limits.h unavailable #include // replacement for limits.h const double ANN_DBL_MAX = MAXDOUBLE; // insert maximum double #else #include #include const double ANN_DBL_MAX = DBL_MAX; #endif #define ANNversion "1.1.2" // ANN version and information #define ANNversionCmt "" #define ANNcopyright "David M. Mount and Sunil Arya" #define ANNlatestRev "Jan 27, 2010" //---------------------------------------------------------------------- // ANNbool // This is a simple boolean type. Although ANSI C++ is supposed // to support the type bool, some compilers do not have it. //---------------------------------------------------------------------- enum ANNbool {ANNfalse = 0, ANNtrue = 1}; // ANN boolean type (non ANSI C++) //---------------------------------------------------------------------- // ANNcoord, ANNdist // ANNcoord and ANNdist are the types used for representing // point coordinates and distances. They can be modified by the // user, with some care. It is assumed that they are both numeric // types, and that ANNdist is generally of an equal or higher type // from ANNcoord. A variable of type ANNdist should be large // enough to store the sum of squared components of a variable // of type ANNcoord for the number of dimensions needed in the // application. For example, the following combinations are // legal: // // ANNcoord ANNdist // --------- ------------------------------- // short short, int, long, float, double // int int, long, float, double // long long, float, double // float float, double // double double // // It is the user's responsibility to make sure that overflow does // not occur in distance calculation. //---------------------------------------------------------------------- typedef double ANNcoord; // coordinate data type typedef double ANNdist; // distance data type //---------------------------------------------------------------------- // ANNidx // ANNidx is a point index. When the data structure is built, the // points are given as an array. Nearest neighbor results are // returned as an integer index into this array. To make it // clearer when this is happening, we define the integer type // ANNidx. Indexing starts from 0. // // For fixed-radius near neighbor searching, it is possible that // there are not k nearest neighbors within the search radius. To // indicate this, the algorithm returns ANN_NULL_IDX as its result. // It should be distinguishable from any valid array index. //---------------------------------------------------------------------- typedef int ANNidx; // point index const ANNidx ANN_NULL_IDX = -1; // a NULL point index //---------------------------------------------------------------------- // Infinite distance: // The code assumes that there is an "infinite distance" which it // uses to initialize distances before performing nearest neighbor // searches. It should be as larger or larger than any legitimate // nearest neighbor distance. // // On most systems, these should be found in the standard include // file or possibly . If you do not have these // file, some suggested values are listed below, assuming 64-bit // long, 32-bit int and 16-bit short. // // ANNdist ANN_DIST_INF Values (see or ) // ------- ------------ ------------------------------------ // double DBL_MAX 1.79769313486231570e+308 // float FLT_MAX 3.40282346638528860e+38 // long LONG_MAX 0x7fffffffffffffff // int INT_MAX 0x7fffffff // short SHRT_MAX 0x7fff //---------------------------------------------------------------------- const ANNdist ANN_DIST_INF = ANN_DBL_MAX; //---------------------------------------------------------------------- // Significant digits for tree dumps: // When floating point coordinates are used, the routine that dumps // a tree needs to know roughly how many significant digits there // are in a ANNcoord, so it can output points to full precision. // This is defined to be ANNcoordPrec. On most systems these // values can be found in the standard include files or // . For integer types, the value is essentially ignored. // // ANNcoord ANNcoordPrec Values (see or ) // -------- ------------ ------------------------------------ // double DBL_DIG 15 // float FLT_DIG 6 // long doesn't matter 19 // int doesn't matter 10 // short doesn't matter 5 //---------------------------------------------------------------------- #ifdef DBL_DIG // number of sig. bits in ANNcoord const int ANNcoordPrec = DBL_DIG; #else const int ANNcoordPrec = 15; // default precision #endif //---------------------------------------------------------------------- // Self match? // In some applications, the nearest neighbor of a point is not // allowed to be the point itself. This occurs, for example, when // computing all nearest neighbors in a set. By setting the // parameter ANN_ALLOW_SELF_MATCH to ANNfalse, the nearest neighbor // is the closest point whose distance from the query point is // strictly positive. //---------------------------------------------------------------------- const ANNbool ANN_ALLOW_SELF_MATCH = ANNtrue; //---------------------------------------------------------------------- // Norms and metrics: // ANN supports any Minkowski norm for defining distance. In // particular, for any p >= 1, the L_p Minkowski norm defines the // length of a d-vector (v0, v1, ..., v(d-1)) to be // // (|v0|^p + |v1|^p + ... + |v(d-1)|^p)^(1/p), // // (where ^ denotes exponentiation, and |.| denotes absolute // value). The distance between two points is defined to be the // norm of the vector joining them. Some common distance metrics // include // // Euclidean metric p = 2 // Manhattan metric p = 1 // Max metric p = infinity // // In the case of the max metric, the norm is computed by taking // the maxima of the absolute values of the components. ANN is // highly "coordinate-based" and does not support general distances // functions (e.g. those obeying just the triangle inequality). It // also does not support distance functions based on // inner-products. // // For the purpose of computing nearest neighbors, it is not // necessary to compute the final power (1/p). Thus the only // component that is used by the program is |v(i)|^p. // // ANN parameterizes the distance computation through the following // macros. (Macros are used rather than procedures for // efficiency.) Recall that the distance between two points is // given by the length of the vector joining them, and the length // or norm of a vector v is given by formula: // // |v| = ROOT(POW(v0) # POW(v1) # ... # POW(v(d-1))) // // where ROOT, POW are unary functions and # is an associative and // commutative binary operator mapping the following types: // // ** POW: ANNcoord --> ANNdist // ** #: ANNdist x ANNdist --> ANNdist // ** ROOT: ANNdist (>0) --> double // // For early termination in distance calculation (partial distance // calculation) we assume that POW and # together are monotonically // increasing on sequences of arguments, meaning that for all // v0..vk and y: // // POW(v0) #...# POW(vk) <= (POW(v0) #...# POW(vk)) # POW(y). // // Incremental Distance Calculation: // The program uses an optimized method of computing distances for // kd-trees and bd-trees, called incremental distance calculation. // It is used when distances are to be updated when only a single // coordinate of a point has been changed. In order to use this, // we assume that there is an incremental update function DIFF(x,y) // for #, such that if: // // s = x0 # ... # xi # ... # xk // // then if s' is equal to s but with xi replaced by y, that is, // // s' = x0 # ... # y # ... # xk // // then the length of s' can be computed by: // // |s'| = |s| # DIFF(xi,y). // // Thus, if # is + then DIFF(xi,y) is (yi-x). For the L_infinity // norm we make use of the fact that in the program this function // is only invoked when y > xi, and hence DIFF(xi,y)=y. // // Finally, for approximate nearest neighbor queries we assume // that POW and ROOT are related such that // // v*ROOT(x) = ROOT(POW(v)*x) // // Here are the values for the various Minkowski norms: // // L_p: p even: p odd: // ------------------------- ------------------------ // POW(v) = v^p POW(v) = |v|^p // ROOT(x) = x^(1/p) ROOT(x) = x^(1/p) // # = + # = + // DIFF(x,y) = y - x DIFF(x,y) = y - x // // L_inf: // POW(v) = |v| // ROOT(x) = x // # = max // DIFF(x,y) = y // // By default the Euclidean norm is assumed. To change the norm, // uncomment the appropriate set of macros below. //---------------------------------------------------------------------- enum ANN_METRIC {ANN_METRIC0, ANN_METRIC1, ANN_METRIC2, ANN_METRICP}; class DLL_API ANN{ public: static ANN_METRIC MetricType; static double MetricPower; }; //---------------------------------------------------------------------- // Use the following for the Euclidean norm //---------------------------------------------------------------------- #define ANN_POW(v) powf(abs((float)v),(float)ANN::MetricPower) //#define ANN_ROOT(x) powf(fabs(x),0.5f) //#define ANN_POW(v) ((v)*(v)) #define ANN_ROOT(x) sqrtf(x) #define ANN_SUM(x,y) ((x) + (y)) #define ANN_DIFF(x,y) ((y) - (x)) //---------------------------------------------------------------------- // Use the following for the L_1 (Manhattan) norm //---------------------------------------------------------------------- #define ANN_POW1(v) abs((float)v) #define ANN_ROOT1(x) abs((float)x) #define ANN_SUM1(x,y) ((x) + (y)) #define ANN_DIFF1(x,y) ((y) - (x)) //---------------------------------------------------------------------- // Use the following for a general L_p norm //---------------------------------------------------------------------- #define ANN_POWp(v) (ANN::MetricPower==1?abs((float)v):powf(fabs(v),(float)ANN::MetricPower)) #define ANN_ROOTp(x) (ANN::MetricPower==1?abs((float)x):powf(fabs(x),1.f/(float)ANN::MetricPower)) #define ANN_SUMp(x,y) ((x) + (y)) #define ANN_DIFFp(x,y) ((y) - (x)) //---------------------------------------------------------------------- // Use the following for the L_infinity (Max) norm //---------------------------------------------------------------------- #define ANN_POW0(v) fabs(v) #define ANN_ROOT0(x) (x) #define ANN_SUM0(x,y) ((x) > (y) ? (x) : (y)) #define ANN_DIFF0(x,y) (y) //---------------------------------------------------------------------- // Array types // The following array types are of basic interest. A point is // just a dimensionless array of coordinates, a point array is a // dimensionless array of points. A distance array is a // dimensionless array of distances and an index array is a // dimensionless array of point indices. The latter two are used // when returning the results of k-nearest neighbor queries. //---------------------------------------------------------------------- typedef ANNcoord* ANNpoint; // a point typedef ANNpoint* ANNpointArray; // an array of points typedef ANNdist* ANNdistArray; // an array of distances typedef ANNidx* ANNidxArray; // an array of point indices //---------------------------------------------------------------------- // Basic point and array utilities: // The following procedures are useful supplements to ANN's nearest // neighbor capabilities. // // annDist(): // Computes the (squared) distance between a pair of points. // Note that this routine is not used internally by ANN for // computing distance calculations. For reasons of efficiency // this is done using incremental distance calculation. Thus, // this routine cannot be modified as a method of changing the // metric. // // Because points (somewhat like strings in C) are stored as // pointers. Consequently, creating and destroying copies of // points may require storage allocation. These procedures do // this. // // annAllocPt() and annDeallocPt(): // Allocate a deallocate storage for a single point, and // return a pointer to it. The argument to AllocPt() is // used to initialize all components. // // annAllocPts() and annDeallocPts(): // Allocate and deallocate an array of points as well a // place to store their coordinates, and initializes the // points to point to their respective coordinates. It // allocates point storage in a contiguous block large // enough to store all the points. It performs no // initialization. // // annCopyPt(): // Creates a copy of a given point, allocating space for // the new point. It returns a pointer to the newly // allocated copy. //---------------------------------------------------------------------- DLL_API ANNdist annDist( int dim, // dimension of space ANNpoint p, // points ANNpoint q); DLL_API ANNpoint annAllocPt( int dim, // dimension ANNcoord c = 0); // coordinate value (all equal) DLL_API ANNpointArray annAllocPts( int n, // number of points int dim); // dimension DLL_API void annDeallocPt( ANNpoint &p); // deallocate 1 point DLL_API void annDeallocPts( ANNpointArray &pa); // point array DLL_API ANNpoint annCopyPt( int dim, // dimension ANNpoint source); // point to copy //---------------------------------------------------------------------- //Overall structure: ANN supports a number of different data structures //for approximate and exact nearest neighbor searching. These are: // // ANNbruteForce A simple brute-force search structure. // ANNkd_tree A kd-tree tree search structure. ANNbd_tree // A bd-tree tree search structure (a kd-tree with shrink // capabilities). // // At a minimum, each of these data structures support k-nearest // neighbor queries. The nearest neighbor query, annkSearch, // returns an integer identifier and the distance to the nearest // neighbor(s) and annRangeSearch returns the nearest points that // lie within a given query ball. // // Each structure is built by invoking the appropriate constructor // and passing it (at a minimum) the array of points, the total // number of points and the dimension of the space. Each structure // is also assumed to support a destructor and member functions // that return basic information about the point set. // // Note that the array of points is not copied by the data // structure (for reasons of space efficiency), and it is assumed // to be constant throughout the lifetime of the search structure. // // The search algorithm, annkSearch, is given the query point (q), // and the desired number of nearest neighbors to report (k), and // the error bound (eps) (whose default value is 0, implying exact // nearest neighbors). It returns two arrays which are assumed to // contain at least k elements: one (nn_idx) contains the indices // (within the point array) of the nearest neighbors and the other // (dd) contains the squared distances to these nearest neighbors. // // The search algorithm, annkFRSearch, is a fixed-radius kNN // search. In addition to a query point, it is given a (squared) // radius bound. (This is done for consistency, because the search // returns distances as squared quantities.) It does two things. // First, it computes the k nearest neighbors within the radius // bound, and second, it returns the total number of points lying // within the radius bound. It is permitted to set k = 0, in which // case it effectively answers a range counting query. If the // error bound epsilon is positive, then the search is approximate // in the sense that it is free to ignore any point that lies // outside a ball of radius r/(1+epsilon), where r is the given // (unsquared) radius bound. // // The generic object from which all the search structures are // dervied is given below. It is a virtual object, and is useless // by itself. //---------------------------------------------------------------------- class DLL_API ANNpointSet { public: virtual ~ANNpointSet() {} // virtual distructor virtual void annkSearch( // approx k near neighbor search ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor array (modified) ANNdistArray dd, // dist to near neighbors (modified) double eps=0.0 // error bound ) = 0; // pure virtual (defined elsewhere) virtual int annkFRSearch( // approx fixed-radius kNN search ANNpoint q, // query point ANNdist sqRad, // squared radius int k = 0, // number of near neighbors to return ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) ANNdistArray dd = NULL, // dist to near neighbors (modified) double eps=0.0 // error bound ) = 0; // pure virtual (defined elsewhere) virtual int theDim() = 0; // return dimension of space virtual int nPoints() = 0; // return number of points // return pointer to points virtual ANNpointArray thePoints() = 0; }; //---------------------------------------------------------------------- // Brute-force nearest neighbor search: // The brute-force search structure is very simple but inefficient. // It has been provided primarily for the sake of comparison with // and validation of the more complex search structures. // // Query processing is the same as described above, but the value // of epsilon is ignored, since all distance calculations are // performed exactly. // // WARNING: This data structure is very slow, and should not be // used unless the number of points is very small. // // Internal information: // --------------------- // This data structure bascially consists of the array of points // (each a pointer to an array of coordinates). The search is // performed by a simple linear scan of all the points. //---------------------------------------------------------------------- class DLL_API ANNbruteForce: public ANNpointSet { int dim; // dimension int n_pts; // number of points ANNpointArray pts; // point array public: ANNbruteForce( // constructor from point array ANNpointArray pa, // point array int n, // number of points int dd); // dimension ~ANNbruteForce(); // destructor void annkSearch( // approx k near neighbor search ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor array (modified) ANNdistArray dd, // dist to near neighbors (modified) double eps=0.0); // error bound int annkFRSearch( // approx fixed-radius kNN search ANNpoint q, // query point ANNdist sqRad, // squared radius int k = 0, // number of near neighbors to return ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) ANNdistArray dd = NULL, // dist to near neighbors (modified) double eps=0.0); // error bound int theDim() // return dimension of space { return dim; } int nPoints() // return number of points { return n_pts; } ANNpointArray thePoints() // return pointer to points { return pts; } }; //---------------------------------------------------------------------- // kd- and bd-tree splitting and shrinking rules // kd-trees supports a collection of different splitting rules. // In addition to the standard kd-tree splitting rule proposed // by Friedman, Bentley, and Finkel, we have introduced a // number of other splitting rules, which seem to perform // as well or better (for the distributions we have tested). // // The splitting methods given below allow the user to tailor // the data structure to the particular data set. They are // are described in greater details in the kd_split.cc source // file. The method ANN_KD_SUGGEST is the method chosen (rather // subjectively) by the implementors as the one giving the // fastest performance, and is the default splitting method. // // As with splitting rules, there are a number of different // shrinking rules. The shrinking rule ANN_BD_NONE does no // shrinking (and hence produces a kd-tree tree). The rule // ANN_BD_SUGGEST uses the implementors favorite rule. //---------------------------------------------------------------------- enum ANNsplitRule { ANN_KD_STD = 0, // the optimized kd-splitting rule ANN_KD_MIDPT = 1, // midpoint split ANN_KD_FAIR = 2, // fair split ANN_KD_SL_MIDPT = 3, // sliding midpoint splitting method ANN_KD_SL_FAIR = 4, // sliding fair split method ANN_KD_SUGGEST = 5}; // the authors' suggestion for best const int ANN_N_SPLIT_RULES = 6; // number of split rules enum ANNshrinkRule { ANN_BD_NONE = 0, // no shrinking at all (just kd-tree) ANN_BD_SIMPLE = 1, // simple splitting ANN_BD_CENTROID = 2, // centroid splitting ANN_BD_SUGGEST = 3}; // the authors' suggested choice const int ANN_N_SHRINK_RULES = 4; // number of shrink rules //---------------------------------------------------------------------- // kd-tree: // The main search data structure supported by ANN is a kd-tree. // The main constructor is given a set of points and a choice of // splitting method to use in building the tree. // // Construction: // ------------- // The constructor is given the point array, number of points, // dimension, bucket size (default = 1), and the splitting rule // (default = ANN_KD_SUGGEST). The point array is not copied, and // is assumed to be kept constant throughout the lifetime of the // search structure. There is also a "load" constructor that // builds a tree from a file description that was created by the // Dump operation. // // Search: // ------- // There are two search methods: // // Standard search (annkSearch()): // Searches nodes in tree-traversal order, always visiting // the closer child first. // Priority search (annkPriSearch()): // Searches nodes in order of increasing distance of the // associated cell from the query point. For many // distributions the standard search seems to work just // fine, but priority search is safer for worst-case // performance. // // Printing: // --------- // There are two methods provided for printing the tree. Print() // is used to produce a "human-readable" display of the tree, with // indenation, which is handy for debugging. Dump() produces a // format that is suitable reading by another program. There is a // "load" constructor, which constructs a tree which is assumed to // have been saved by the Dump() procedure. // // Performance and Structure Statistics: // ------------------------------------- // The procedure getStats() collects statistics information on the // tree (its size, height, etc.) See ANNperf.h for information on // the stats structure it returns. // // Internal information: // --------------------- // The data structure consists of three major chunks of storage. // The first (implicit) storage are the points themselves (pts), // which have been provided by the users as an argument to the // constructor, or are allocated dynamically if the tree is built // using the load constructor). These should not be changed during // the lifetime of the search structure. It is the user's // responsibility to delete these after the tree is destroyed. // // The second is the tree itself (which is dynamically allocated in // the constructor) and is given as a pointer to its root node // (root). These nodes are automatically deallocated when the tree // is deleted. See the file src/kd_tree.h for further information // on the structure of the tree nodes. // // Each leaf of the tree does not contain a pointer directly to a // point, but rather contains a pointer to a "bucket", which is an // array consisting of point indices. The third major chunk of // storage is an array (pidx), which is a large array in which all // these bucket subarrays reside. (The reason for storing them // separately is the buckets are typically small, but of varying // sizes. This was done to avoid fragmentation.) This array is // also deallocated when the tree is deleted. // // In addition to this, the tree consists of a number of other // pieces of information which are used in searching and for // subsequent tree operations. These consist of the following: // // dim Dimension of space // n_pts Number of points currently in the tree // n_max Maximum number of points that are allowed // in the tree // bkt_size Maximum bucket size (no. of points per leaf) // bnd_box_lo Bounding box low point // bnd_box_hi Bounding box high point // splitRule Splitting method used // //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Some types and objects used by kd-tree functions // See src/kd_tree.h and src/kd_tree.cpp for definitions //---------------------------------------------------------------------- class ANNkdStats; // stats on kd-tree class ANNkd_node; // generic node in a kd-tree typedef ANNkd_node* ANNkd_ptr; // pointer to a kd-tree node class DLL_API ANNkd_tree: public ANNpointSet { protected: int dim; // dimension of space int n_pts; // number of points in tree int bkt_size; // bucket size ANNpointArray pts; // the points ANNidxArray pidx; // point indices (to pts array) ANNkd_ptr root; // root of kd-tree ANNpoint bnd_box_lo; // bounding box low point ANNpoint bnd_box_hi; // bounding box high point void SkeletonTree( // construct skeleton tree int n, // number of points int dd, // dimension int bs, // bucket size ANNpointArray pa = NULL, // point array (optional) ANNidxArray pi = NULL); // point indices (optional) public: ANNkd_tree( // build skeleton tree int n = 0, // number of points int dd = 0, // dimension int bs = 1); // bucket size ANNkd_tree( // build from point array ANNpointArray pa, // point array int n, // number of points int dd, // dimension int bs = 1, // bucket size ANNsplitRule split = ANN_KD_SUGGEST); // splitting method ANNkd_tree( // build from dump file std::istream& in); // input stream for dump file ~ANNkd_tree(); // tree destructor void annkSearch( // approx k near neighbor search ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor array (modified) ANNdistArray dd, // dist to near neighbors (modified) double eps=0.0); // error bound void annkPriSearch( // priority k near neighbor search ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor array (modified) ANNdistArray dd, // dist to near neighbors (modified) double eps=0.0); // error bound int annkFRSearch( // approx fixed-radius kNN search ANNpoint q, // the query point ANNdist sqRad, // squared radius of query ball int k, // number of neighbors to return ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) ANNdistArray dd = NULL, // dist to near neighbors (modified) double eps=0.0); // error bound int theDim() // return dimension of space { return dim; } int nPoints() // return number of points { return n_pts; } ANNpointArray thePoints() // return pointer to points { return pts; } virtual void Print( // print the tree (for debugging) ANNbool with_pts, // print points as well? std::ostream& out); // output stream virtual void Dump( // dump entire tree ANNbool with_pts, // print points as well? std::ostream& out); // output stream virtual void getStats( // compute tree statistics ANNkdStats& st); // the statistics (modified) }; //---------------------------------------------------------------------- // Box decomposition tree (bd-tree) // The bd-tree is inherited from a kd-tree. The main difference // in the bd-tree and the kd-tree is a new type of internal node // called a shrinking node (in the kd-tree there is only one type // of internal node, a splitting node). The shrinking node // makes it possible to generate balanced trees in which the // cells have bounded aspect ratio, by allowing the decomposition // to zoom in on regions of dense point concentration. Although // this is a nice idea in theory, few point distributions are so // densely clustered that this is really needed. //---------------------------------------------------------------------- class DLL_API ANNbd_tree: public ANNkd_tree { public: ANNbd_tree( // build skeleton tree int n, // number of points int dd, // dimension int bs = 1) // bucket size : ANNkd_tree(n, dd, bs) {} // build base kd-tree ANNbd_tree( // build from point array ANNpointArray pa, // point array int n, // number of points int dd, // dimension int bs = 1, // bucket size ANNsplitRule split = ANN_KD_SUGGEST, // splitting rule ANNshrinkRule shrink = ANN_BD_SUGGEST); // shrinking rule ANNbd_tree( // build from dump file std::istream& in); // input stream for dump file }; //---------------------------------------------------------------------- // Other functions // annMaxPtsVisit Sets a limit on the maximum number of points // to visit in the search. // annClose Can be called when all use of ANN is finished. // It clears up a minor memory leak. //---------------------------------------------------------------------- DLL_API void annMaxPtsVisit( // max. pts to visit in search int maxPts); // the limit DLL_API void annClose(); // called to end use of ANN #endif mldemos-0.4.3/_3rdParty/ANN/ANNperf.h000066400000000000000000000203521172143270300171050ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: ANNperf.h // Programmer: Sunil Arya and David Mount // Last modified: 03/04/98 (Release 0.1) // Description: Include file for ANN performance stats // // Some of the code for statistics gathering has been adapted // from the SmplStat.h package in the g++ library. //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Added ANN_ prefix to avoid name conflicts. //---------------------------------------------------------------------- #ifndef ANNperf_H #define ANNperf_H //---------------------------------------------------------------------- // basic includes //---------------------------------------------------------------------- #include // basic ANN includes //---------------------------------------------------------------------- // kd-tree stats object // This object is used for collecting information about a kd-tree // or bd-tree. //---------------------------------------------------------------------- class ANNkdStats { // stats on kd-tree public: int dim; // dimension of space int n_pts; // no. of points int bkt_size; // bucket size int n_lf; // no. of leaves (including trivial) int n_tl; // no. of trivial leaves (no points) int n_spl; // no. of splitting nodes int n_shr; // no. of shrinking nodes (for bd-trees) int depth; // depth of tree float sum_ar; // sum of leaf aspect ratios float avg_ar; // average leaf aspect ratio // // reset stats void reset(int d=0, int n=0, int bs=0) { dim = d; n_pts = n; bkt_size = bs; n_lf = n_tl = n_spl = n_shr = depth = 0; sum_ar = avg_ar = 0.0; } ANNkdStats() // basic constructor { reset(); } void merge(const ANNkdStats &st); // merge stats from child }; //---------------------------------------------------------------------- // ANNsampStat // A sample stat collects numeric (double) samples and returns some // simple statistics. Its main functions are: // // reset() Reset to no samples. // += x Include sample x. // samples() Return number of samples. // mean() Return mean of samples. // stdDev() Return standard deviation // min() Return minimum of samples. // max() Return maximum of samples. //---------------------------------------------------------------------- class DLL_API ANNsampStat { int n; // number of samples double sum; // sum double sum2; // sum of squares double minVal, maxVal; // min and max public : void reset() // reset everything { n = 0; sum = sum2 = 0; minVal = ANN_DBL_MAX; maxVal = -ANN_DBL_MAX; } ANNsampStat() { reset(); } // constructor void operator+=(double x) // add sample { n++; sum += x; sum2 += x*x; if (x < minVal) minVal = x; if (x > maxVal) maxVal = x; } int samples() { return n; } // number of samples double mean() { return sum/n; } // mean // standard deviation double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));} double min() { return minVal; } // minimum double max() { return maxVal; } // maximum }; //---------------------------------------------------------------------- // Operation count updates //---------------------------------------------------------------------- #ifdef ANN_PERF #define ANN_FLOP(n) {ann_Nfloat_ops += (n);} #define ANN_LEAF(n) {ann_Nvisit_lfs += (n);} #define ANN_SPL(n) {ann_Nvisit_spl += (n);} #define ANN_SHR(n) {ann_Nvisit_shr += (n);} #define ANN_PTS(n) {ann_Nvisit_pts += (n);} #define ANN_COORD(n) {ann_Ncoord_hts += (n);} #else #define ANN_FLOP(n) #define ANN_LEAF(n) #define ANN_SPL(n) #define ANN_SHR(n) #define ANN_PTS(n) #define ANN_COORD(n) #endif //---------------------------------------------------------------------- // Performance statistics // The following data and routines are used for computing performance // statistics for nearest neighbor searching. Because these routines // can slow the code down, they can be activated and deactiviated by // defining the ANN_PERF variable, by compiling with the option: // -DANN_PERF //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Global counters for performance measurement // // visit_lfs The number of leaf nodes visited in the // tree. // // visit_spl The number of splitting nodes visited in the // tree. // // visit_shr The number of shrinking nodes visited in the // tree. // // visit_pts The number of points visited in all the // leaf nodes visited. Equivalently, this // is the number of points for which distance // calculations are performed. // // coord_hts The number of times a coordinate of a // data point is accessed. This is generally // less than visit_pts*d if partial distance // calculation is used. This count is low // in the sense that if a coordinate is hit // many times in the same routine we may // count it only once. // // float_ops The number of floating point operations. // This includes all operations in the heap // as well as distance calculations to boxes. // // average_err The average error of each query (the // error of the reported point to the true // nearest neighbor). For k nearest neighbors // the error is computed k times. // // rank_err The rank error of each query (the difference // in the rank of the reported point and its // true rank). // // data_pts The number of data points. This is not // a counter, but used in stats computation. //---------------------------------------------------------------------- extern int ann_Ndata_pts; // number of data points extern int ann_Nvisit_lfs; // number of leaf nodes visited extern int ann_Nvisit_spl; // number of splitting nodes visited extern int ann_Nvisit_shr; // number of shrinking nodes visited extern int ann_Nvisit_pts; // visited points for one query extern int ann_Ncoord_hts; // coordinate hits for one query extern int ann_Nfloat_ops; // floating ops for one query extern ANNsampStat ann_visit_lfs; // stats on leaf nodes visits extern ANNsampStat ann_visit_spl; // stats on splitting nodes visits extern ANNsampStat ann_visit_shr; // stats on shrinking nodes visits extern ANNsampStat ann_visit_nds; // stats on total nodes visits extern ANNsampStat ann_visit_pts; // stats on points visited extern ANNsampStat ann_coord_hts; // stats on coordinate hits extern ANNsampStat ann_float_ops; // stats on floating ops //---------------------------------------------------------------------- // The following need to be part of the public interface, because // they are accessed outside the DLL in ann_test.cpp. //---------------------------------------------------------------------- DLL_API extern ANNsampStat ann_average_err; // average error DLL_API extern ANNsampStat ann_rank_err; // rank error //---------------------------------------------------------------------- // Declaration of externally accessible routines for statistics //---------------------------------------------------------------------- DLL_API void annResetStats(int data_size); // reset stats for a set of queries DLL_API void annResetCounts(); // reset counts for one queries DLL_API void annUpdateStats(); // update stats with current counts DLL_API void annPrintStats(ANNbool validate); // print statistics for a run #endif mldemos-0.4.3/_3rdParty/ANN/ANNx.h000066400000000000000000000152131172143270300164200ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: ANNx.h // Programmer: Sunil Arya and David Mount // Description: Internal include file for ANN // Last modified: 01/27/10 (Version 1.1.2) // // These declarations are of use in manipulating some of // the internal data objects appearing in ANN, but are not // needed for applications just using the nearest neighbor // search. // // Typical users of ANN should not need to access this file. //---------------------------------------------------------------------- // Copyright (c) 1997-2010 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc. // Revision 1.1.2 01/27/10 // Fixed minor compilation bugs for new versions of gcc //---------------------------------------------------------------------- #ifndef ANNx_H #define ANNx_H #include // I/O manipulators #include // ANN includes //---------------------------------------------------------------------- // Global constants and types //---------------------------------------------------------------------- enum {ANN_LO=0, ANN_HI=1}; // splitting indices enum {ANN_IN=0, ANN_OUT=1}; // shrinking indices // what to do in case of error enum ANNerr {ANNwarn = 0, ANNabort = 1}; //---------------------------------------------------------------------- // Maximum number of points to visit // We have an option for terminating the search early if the // number of points visited exceeds some threshold. If the // threshold is 0 (its default) this means there is no limit // and the algorithm applies its normal termination condition. //---------------------------------------------------------------------- extern int ANNmaxPtsVisited; // maximum number of pts visited extern int ANNptsVisited; // number of pts visited in search //---------------------------------------------------------------------- // Global function declarations //---------------------------------------------------------------------- void annError( // ANN error routine const char* msg, // error message ANNerr level); // level of error void annPrintPt( // print a point ANNpoint pt, // the point int dim, // the dimension std::ostream &out); // output stream //---------------------------------------------------------------------- // Orthogonal (axis aligned) rectangle // Orthogonal rectangles are represented by two points, one // for the lower left corner (min coordinates) and the other // for the upper right corner (max coordinates). // // The constructor initializes from either a pair of coordinates, // pair of points, or another rectangle. Note that all constructors // allocate new point storage. The destructor deallocates this // storage. // // BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE. // (C++'s default copy constructor will not allocate new point // storage, then on return the destructor free's storage, and then // you get into big trouble in the calling procedure.) //---------------------------------------------------------------------- class ANNorthRect { public: ANNpoint lo; // rectangle lower bounds ANNpoint hi; // rectangle upper bounds // ANNorthRect( // basic constructor int dd, // dimension of space ANNcoord l=0, // default is empty ANNcoord h=0) { lo = annAllocPt(dd, l); hi = annAllocPt(dd, h); } ANNorthRect( // (almost a) copy constructor int dd, // dimension const ANNorthRect &r) // rectangle to copy { lo = annCopyPt(dd, r.lo); hi = annCopyPt(dd, r.hi); } ANNorthRect( // construct from points int dd, // dimension ANNpoint l, // low point ANNpoint h) // hight point { lo = annCopyPt(dd, l); hi = annCopyPt(dd, h); } ~ANNorthRect() // destructor { annDeallocPt(lo); annDeallocPt(hi); } ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle? }; void annAssignRect( // assign one rect to another int dim, // dimension (both must be same) ANNorthRect &dest, // destination (modified) const ANNorthRect &source); // source //---------------------------------------------------------------------- // Orthogonal (axis aligned) halfspace // An orthogonal halfspace is represented by an integer cutting // dimension cd, coordinate cutting value, cv, and side, sd, which is // either +1 or -1. Our convention is that point q lies in the (closed) // halfspace if (q[cd] - cv)*sd >= 0. //---------------------------------------------------------------------- class ANNorthHalfSpace { public: int cd; // cutting dimension ANNcoord cv; // cutting value int sd; // which side // ANNorthHalfSpace() // default constructor { cd = 0; cv = 0; sd = 0; } ANNorthHalfSpace( // basic constructor int cdd, // dimension of space ANNcoord cvv, // cutting value int sdd) // side { cd = cdd; cv = cvv; sd = sdd; } ANNbool in(ANNpoint q) const // is q inside halfspace? { return (ANNbool) ((q[cd] - cv)*sd >= 0); } ANNbool out(ANNpoint q) const // is q outside halfspace? { return (ANNbool) ((q[cd] - cv)*sd < 0); } ANNdist dist(ANNpoint q) const // (squared) distance from q { switch(ANN::MetricType) { case ANN_METRIC0: return (ANNdist) ANN_POW0(q[cd] - cv); case ANN_METRIC1: return (ANNdist) ANN_POW1(q[cd] - cv); case ANN_METRIC2: return (ANNdist) ANN_POW(q[cd] - cv); case ANN_METRICP: return (ANNdist) ANN_POWp(q[cd] - cv); } return (ANNdist) ANN_POW(q[cd] - cv); } void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i] { cd = d; cv = p[d]; sd = +1; } void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i] { cd = d; cv = p[d]; sd = -1; } void project(ANNpoint &q) // project q (modified) onto halfspace { if (out(q)) q[cd] = cv; } }; // array of halfspaces typedef ANNorthHalfSpace *ANNorthHSArray; #endif mldemos-0.4.3/_3rdParty/ANN/bd_fix_rad_search.cpp000066400000000000000000000061351172143270300215600ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: bd_fix_rad_search.cpp // Programmer: David Mount // Description: Standard bd-tree search // Last modified: 05/03/05 (Version 1.1) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 1.1 05/03/05 // Initial release //---------------------------------------------------------------------- #include "bd_tree.h" // bd-tree declarations #include "kd_fix_rad_search.h" // kd-tree FR search declarations //---------------------------------------------------------------------- // Approximate searching for bd-trees. // See the file kd_FR_search.cpp for general information on the // approximate nearest neighbor search algorithm. Here we // include the extensions for shrinking nodes. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // bd_shrink::ann_FR_search - search a shrinking node //---------------------------------------------------------------------- void ANNbd_shrink::ann_FR_search(ANNdist box_dist) { // check dist calc term cond. if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; ANNdist inner_dist = 0; // distance to inner box for (int i = 0; i < n_bnds; i++) { // is query point in the box? if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side? // add to inner distance switch(ANN::MetricType) { case ANN_METRIC0: inner_dist = (ANNdist) ANN_SUM0(inner_dist, bnds[i].dist(ANNkdFRQ)); break; case ANN_METRIC1: inner_dist = (ANNdist) ANN_SUM1(inner_dist, bnds[i].dist(ANNkdFRQ)); break; case ANN_METRIC2: inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ)); break; case ANN_METRICP: inner_dist = (ANNdist) ANN_SUMp(inner_dist, bnds[i].dist(ANNkdFRQ)); break; } } } if (inner_dist <= box_dist) { // if inner box is closer child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child } else { // if outer box is closer child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child } ANN_FLOP(3*n_bnds) // increment floating ops ANN_SHR(1) // one more shrinking node } mldemos-0.4.3/_3rdParty/ANN/bd_pr_search.cpp000066400000000000000000000061621172143270300205650ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: bd_pr_search.cpp // Programmer: David Mount // Description: Priority search for bd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- //History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #include "bd_tree.h" // bd-tree declarations #include "kd_pr_search.h" // kd priority search declarations //---------------------------------------------------------------------- // Approximate priority searching for bd-trees. // See the file kd_pr_search.cc for general information on the // approximate nearest neighbor priority search algorithm. Here // we include the extensions for shrinking nodes. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // bd_shrink::ann_search - search a shrinking node //---------------------------------------------------------------------- void ANNbd_shrink::ann_pri_search(ANNdist box_dist) { ANNdist inner_dist = 0; // distance to inner box for (int i = 0; i < n_bnds; i++) { // is query point in the box? if (bnds[i].out(ANNprQ)) { // outside this bounding side? // add to inner distance switch(ANN::MetricType) { case ANN_METRIC0: inner_dist = (ANNdist) ANN_SUM0(inner_dist, bnds[i].dist(ANNprQ)); break; case ANN_METRIC1: inner_dist = (ANNdist) ANN_SUM1(inner_dist, bnds[i].dist(ANNprQ)); break; case ANN_METRIC2: inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ)); break; case ANN_METRICP: inner_dist = (ANNdist) ANN_SUMp(inner_dist, bnds[i].dist(ANNprQ)); break; } } } if (inner_dist <= box_dist) { // if inner box is closer if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial ANNprBoxPQ->insert(box_dist,child[ANN_OUT]); // continue with inner child child[ANN_IN]->ann_pri_search(inner_dist); } else { // if outer box is closer if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial ANNprBoxPQ->insert(inner_dist,child[ANN_IN]); // continue with outer child child[ANN_OUT]->ann_pri_search(box_dist); } ANN_FLOP(3*n_bnds) // increment floating ops ANN_SHR(1) // one more shrinking node } mldemos-0.4.3/_3rdParty/ANN/bd_search.cpp000066400000000000000000000060621172143270300200630ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: bd_search.cpp // Programmer: David Mount // Description: Standard bd-tree search // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #include "bd_tree.h" // bd-tree declarations #include "kd_search.h" // kd-tree search declarations //---------------------------------------------------------------------- // Approximate searching for bd-trees. // See the file kd_search.cpp for general information on the // approximate nearest neighbor search algorithm. Here we // include the extensions for shrinking nodes. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // bd_shrink::ann_search - search a shrinking node //---------------------------------------------------------------------- void ANNbd_shrink::ann_search(ANNdist box_dist) { // check dist calc term cond. if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; ANNdist inner_dist = 0; // distance to inner box for (int i = 0; i < n_bnds; i++) { // is query point in the box? if (bnds[i].out(ANNkdQ)) { // outside this bounding side? // add to inner distance switch(ANN::MetricType) { case ANN_METRIC0: inner_dist = (ANNdist) ANN_SUM0(inner_dist, bnds[i].dist(ANNkdQ)); break; case ANN_METRIC1: inner_dist = (ANNdist) ANN_SUM1(inner_dist, bnds[i].dist(ANNkdQ)); break; case ANN_METRIC2: inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ)); break; case ANN_METRICP: inner_dist = (ANNdist) ANN_SUMp(inner_dist, bnds[i].dist(ANNkdQ)); break; } } } if (inner_dist <= box_dist) { // if inner box is closer child[ANN_IN]->ann_search(inner_dist); // search inner child first child[ANN_OUT]->ann_search(box_dist); // ...then outer child } else { // if outer box is closer child[ANN_OUT]->ann_search(box_dist); // search outer child first child[ANN_IN]->ann_search(inner_dist); // ...then outer child } ANN_FLOP(3*n_bnds) // increment floating ops ANN_SHR(1) // one more shrinking node } mldemos-0.4.3/_3rdParty/ANN/bd_tree.cpp000066400000000000000000000404011172143270300175500ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: bd_tree.cpp // Programmer: David Mount // Description: Basic methods for bd-trees. // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision l.0 04/01/05 // Fixed centroid shrink threshold condition to depend on the // dimension. // Moved dump routine to kd_dump.cpp. //---------------------------------------------------------------------- #include "bd_tree.h" // bd-tree declarations #include "kd_util.h" // kd-tree utilities #include "kd_split.h" // kd-tree splitting rules #include // performance evaluation //---------------------------------------------------------------------- // Printing a bd-tree // These routines print a bd-tree. See the analogous procedure // in kd_tree.cpp for more information. //---------------------------------------------------------------------- void ANNbd_shrink::print( // print shrinking node int level, // depth of node in tree ostream &out) // output stream { child[ANN_OUT]->print(level+1, out); // print out-child out << " "; for (int i = 0; i < level; i++) // print indentation out << ".."; out << "Shrink"; for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line if (j % 2 == 0) { out << "\n"; // newline and indentation for (int i = 0; i < level+2; i++) out << " "; } out << " ([" << bnds[j].cd << "]" << (bnds[j].sd > 0 ? ">=" : "< ") << bnds[j].cv << ")"; } out << "\n"; child[ANN_IN]->print(level+1, out); // print in-child } //---------------------------------------------------------------------- // kd_tree statistics utility (for performance evaluation) // This routine computes various statistics information for // shrinking nodes. See file kd_tree.cpp for more information. //---------------------------------------------------------------------- void ANNbd_shrink::getStats( // get subtree statistics int dim, // dimension of space ANNkdStats &st, // stats (modified) ANNorthRect &bnd_box) // bounding box { ANNkdStats ch_stats; // stats for children ANNorthRect inner_box(dim); // inner box of shrink annBnds2Box(bnd_box, // enclosing box dim, // dimension n_bnds, // number of bounds bnds, // bounds array inner_box); // inner box (modified) // get stats for inner child ch_stats.reset(); // reset child[ANN_IN]->getStats(dim, ch_stats, inner_box); st.merge(ch_stats); // merge them // get stats for outer child ch_stats.reset(); // reset child[ANN_OUT]->getStats(dim, ch_stats, bnd_box); st.merge(ch_stats); // merge them st.depth++; // increment depth st.n_shr++; // increment number of shrinks } //---------------------------------------------------------------------- // bd-tree constructor // This is the main constructor for bd-trees given a set of points. // It first builds a skeleton kd-tree as a basis, then computes the // bounding box of the data points, and then invokes rbd_tree() to // actually build the tree, passing it the appropriate splitting // and shrinking information. //---------------------------------------------------------------------- ANNkd_ptr rbd_tree( // recursive construction of bd-tree ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space int bsp, // bucket space ANNorthRect &bnd_box, // bounding box for current node ANNkd_splitter splitter, // splitting routine ANNshrinkRule shrink); // shrinking rule ANNbd_tree::ANNbd_tree( // construct from point array ANNpointArray pa, // point array (with at least n pts) int n, // number of points int dd, // dimension int bs, // bucket size ANNsplitRule split, // splitting rule ANNshrinkRule shrink) // shrinking rule : ANNkd_tree(n, dd, bs) // build skeleton base tree { pts = pa; // where the points are if (n == 0) return; // no points--no sweat ANNorthRect bnd_box(dd); // bounding box for points // construct bounding rectangle annEnclRect(pa, pidx, n, dd, bnd_box); // copy to tree structure bnd_box_lo = annCopyPt(dd, bnd_box.lo); bnd_box_hi = annCopyPt(dd, bnd_box.hi); switch (split) { // build by rule case ANN_KD_STD: // standard kd-splitting rule root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink); break; case ANN_KD_MIDPT: // midpoint split root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink); break; case ANN_KD_SUGGEST: // best (in our opinion) case ANN_KD_SL_MIDPT: // sliding midpoint split root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink); break; case ANN_KD_FAIR: // fair split root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink); break; case ANN_KD_SL_FAIR: // sliding fair split root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split, shrink); break; default: annError("Illegal splitting method", ANNabort); } } //---------------------------------------------------------------------- // Shrinking rules //---------------------------------------------------------------------- enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods //---------------------------------------------------------------------- // trySimpleShrink - Attempt a simple shrink // // We compute the tight bounding box of the points, and compute // the 2*dim ``gaps'' between the sides of the tight box and the // bounding box. If any of the gaps is large enough relative to // the longest side of the tight bounding box, then we shrink // all sides whose gaps are large enough. (The reason for // comparing against the tight bounding box, is that after // shrinking the longest box size will decrease, and if we use // the standard bounding box, we may decide to shrink twice in // a row. Since the tight box is fixed, we cannot shrink twice // consecutively.) //---------------------------------------------------------------------- const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1) const int BD_CT_THRESH = 2; // min number of shrink sides ANNdecomp trySimpleShrink( // try a simple shrink ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space const ANNorthRect &bnd_box, // current bounding box ANNorthRect &inner_box) // inner box if shrinking (returned) { int i; // compute tight bounding box annEnclRect(pa, pidx, n, dim, inner_box); ANNcoord max_length = 0; // find longest box side for (i = 0; i < dim; i++) { ANNcoord length = inner_box.hi[i] - inner_box.lo[i]; if (length > max_length) { max_length = length; } } int shrink_ct = 0; // number of sides we shrunk for (i = 0; i < dim; i++) { // select which sides to shrink // gap between boxes ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i]; // big enough gap to shrink? if (gap_hi < max_length*BD_GAP_THRESH) inner_box.hi[i] = bnd_box.hi[i]; // no - expand else shrink_ct++; // yes - shrink this side // repeat for high side ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i]; if (gap_lo < max_length*BD_GAP_THRESH) inner_box.lo[i] = bnd_box.lo[i]; // no - expand else shrink_ct++; // yes - shrink this side } if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides? return SHRINK; else return SPLIT; } //---------------------------------------------------------------------- // tryCentroidShrink - Attempt a centroid shrink // // We repeatedly apply the splitting rule, always to the larger subset // of points, until the number of points decreases by the constant // fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC // splits for this to happen, then we shrink to the final inner box // Otherwise we split. //---------------------------------------------------------------------- const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed const float BD_FRACTION = 0.5; // ...to reduce points by this fraction // ...This must be < 1. ANNdecomp tryCentroidShrink( // try a centroid shrink ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space const ANNorthRect &bnd_box, // current bounding box ANNkd_splitter splitter, // splitting procedure ANNorthRect &inner_box) // inner box if shrinking (returned) { int n_sub = n; // number of points in subset int n_goal = (int) (n*BD_FRACTION); // number of point in goal int n_splits = 0; // number of splits needed // initialize inner box to bounding box annAssignRect(dim, inner_box, bnd_box); while (n_sub > n_goal) { // keep splitting until goal reached int cd; // cut dim from splitter (ignored) ANNcoord cv; // cut value from splitter (ignored) int n_lo; // number of points on low side // invoke splitting procedure (*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo); n_splits++; // increment split count if (n_lo >= n_sub/2) { // most points on low side inner_box.hi[cd] = cv; // collapse high side n_sub = n_lo; // recurse on lower points } else { // most points on high side inner_box.lo[cd] = cv; // collapse low side pidx += n_lo; // recurse on higher points n_sub -= n_lo; } } if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits return SHRINK; // shrink to final subset else return SPLIT; } //---------------------------------------------------------------------- // selectDecomp - select which decomposition to use //---------------------------------------------------------------------- ANNdecomp selectDecomp( // select decomposition method ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space const ANNorthRect &bnd_box, // current bounding box ANNkd_splitter splitter, // splitting procedure ANNshrinkRule shrink, // shrinking rule ANNorthRect &inner_box) // inner box if shrinking (returned) { ANNdecomp decomp = SPLIT; // decomposition switch (shrink) { // check shrinking rule case ANN_BD_NONE: // no shrinking allowed decomp = SPLIT; break; case ANN_BD_SUGGEST: // author's suggestion case ANN_BD_SIMPLE: // simple shrink decomp = trySimpleShrink( pa, pidx, // points and indices n, dim, // number of points and dimension bnd_box, // current bounding box inner_box); // inner box if shrinking (returned) break; case ANN_BD_CENTROID: // centroid shrink decomp = tryCentroidShrink( pa, pidx, // points and indices n, dim, // number of points and dimension bnd_box, // current bounding box splitter, // splitting procedure inner_box); // inner box if shrinking (returned) break; default: annError("Illegal shrinking rule", ANNabort); } return decomp; } //---------------------------------------------------------------------- // rbd_tree - recursive procedure to build a bd-tree // // This is analogous to rkd_tree, but for bd-trees. See the // procedure rkd_tree() in kd_split.cpp for more information. // // If the number of points falls below the bucket size, then a // leaf node is created for the points. Otherwise we invoke the // procedure selectDecomp() which determines whether we are to // split or shrink. If splitting is chosen, then we essentially // do exactly as rkd_tree() would, and invoke the specified // splitting procedure to the points. Otherwise, the selection // procedure returns a bounding box, from which we extract the // appropriate shrinking bounds, and create a shrinking node. // Finally the points are subdivided, and the procedure is // invoked recursively on the two subsets to form the children. //---------------------------------------------------------------------- ANNkd_ptr rbd_tree( // recursive construction of bd-tree ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space int bsp, // bucket space ANNorthRect &bnd_box, // bounding box for current node ANNkd_splitter splitter, // splitting routine ANNshrinkRule shrink) // shrinking rule { ANNdecomp decomp; // decomposition method ANNorthRect inner_box(dim); // inner box (if shrinking) if (n <= bsp) { // n small, make a leaf node if (n == 0) // empty leaf node return KD_TRIVIAL; // return (canonical) empty leaf else // construct the node and return return new ANNkd_leaf(n, pidx); } decomp = selectDecomp( // select decomposition method pa, pidx, // points and indices n, dim, // number of points and dimension bnd_box, // current bounding box splitter, shrink, // splitting/shrinking methods inner_box); // inner box if shrinking (returned) if (decomp == SPLIT) { // split selected int cd; // cutting dimension ANNcoord cv; // cutting value int n_lo; // number on low side of cut // invoke splitting procedure (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension ANNcoord hv = bnd_box.hi[cd]; bnd_box.hi[cd] = cv; // modify bounds for left subtree ANNkd_ptr lo = rbd_tree( // build left subtree pa, pidx, n_lo, // ...from pidx[0..n_lo-1] dim, bsp, bnd_box, splitter, shrink); bnd_box.hi[cd] = hv; // restore bounds bnd_box.lo[cd] = cv; // modify bounds for right subtree ANNkd_ptr hi = rbd_tree( // build right subtree pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] dim, bsp, bnd_box, splitter, shrink); bnd_box.lo[cd] = lv; // restore bounds // create the splitting node return new ANNkd_split(cd, cv, lv, hv, lo, hi); } else { // shrink selected int n_in; // number of points in box int n_bnds; // number of bounding sides annBoxSplit( // split points around inner box pa, // points to split pidx, // point indices n, // number of points dim, // dimension inner_box, // inner box n_in); // number of points inside (returned) ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1] pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink); ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n] pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink); ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and // ...freed in bd_shrink destroyer) annBox2Bnds( // convert inner box to bounds inner_box, // inner box bnd_box, // enclosing box dim, // dimension n_bnds, // number of bounds (returned) bnds); // bounds array (modified) // return shrinking node return new ANNbd_shrink(n_bnds, bnds, in, out); } } mldemos-0.4.3/_3rdParty/ANN/bd_tree.h000066400000000000000000000077411172143270300172270ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: bd_tree.h // Programmer: David Mount // Description: Declarations for standard bd-tree routines // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Changed IN, OUT to ANN_IN, ANN_OUT //---------------------------------------------------------------------- #ifndef ANN_bd_tree_H #define ANN_bd_tree_H #include // all ANN includes #include "kd_tree.h" // kd-tree includes //---------------------------------------------------------------------- // bd-tree shrinking node. // The main addition in the bd-tree is the shrinking node, which // is declared here. // // Shrinking nodes are defined by list of orthogonal halfspaces. // These halfspaces define a (possibly unbounded) orthogonal // rectangle. There are two children, in and out. Points that // lie within this rectangle are stored in the in-child, and the // other points are stored in the out-child. // // We use a list of orthogonal halfspaces rather than an // orthogonal rectangle object because typically the number of // sides of the shrinking box will be much smaller than the // worst case bound of 2*dim. // // BEWARE: Note that constructor just copies the pointer to the // bounding array, but the destructor deallocates it. This is // rather poor practice, but happens to be convenient. The list // is allocated in the bd-tree building procedure rbd_tree() just // prior to construction, and is used for no other purposes. // // WARNING: In the near neighbor searching code it is assumed that // the list of bounding halfspaces is irredundant, meaning that there // are no two distinct halfspaces in the list with the same outward // pointing normals. //---------------------------------------------------------------------- class ANNbd_shrink : public ANNkd_node // splitting node of a kd-tree { int n_bnds; // number of bounding halfspaces ANNorthHSArray bnds; // list of bounding halfspaces ANNkd_ptr child[2]; // in and out children public: ANNbd_shrink( // constructor int nb, // number of bounding halfspaces ANNorthHSArray bds, // list of bounding halfspaces ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL) // children { n_bnds = nb; // cutting dimension bnds = bds; // assign bounds child[ANN_IN] = ic; // set children child[ANN_OUT] = oc; } ~ANNbd_shrink() // destructor { if (child[ANN_IN]!= NULL && child[ANN_IN]!= KD_TRIVIAL) delete child[ANN_IN]; if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL) delete child[ANN_OUT]; if (bnds != NULL) delete [] bnds; // delete bounds } virtual void getStats( // get tree statistics int dim, // dimension of space ANNkdStats &st, // statistics ANNorthRect &bnd_box); // bounding box virtual void print(int level, ostream &out);// print node virtual void dump(ostream &out); // dump node virtual void ann_search(ANNdist); // standard search virtual void ann_pri_search(ANNdist); // priority search virtual void ann_FR_search(ANNdist); // fixed-radius search }; #endif mldemos-0.4.3/_3rdParty/ANN/brute.cpp000066400000000000000000000101521172143270300172650ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: brute.cpp // Programmer: Sunil Arya and David Mount // Description: Brute-force nearest neighbors // Last modified: 05/03/05 (Version 1.1) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.1 05/03/05 // Added fixed-radius kNN search //---------------------------------------------------------------------- #include // all ANN includes #include "pr_queue_k.h" // k element priority queue //---------------------------------------------------------------------- // Brute-force search simply stores a pointer to the list of // data points and searches linearly for the nearest neighbor. // The k nearest neighbors are stored in a k-element priority // queue (which is implemented in a pretty dumb way as well). // // If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance // zero are not considered. // // Note that the error bound eps is passed in, but it is ignored. // These routines compute exact nearest neighbors (which is needed // for validation purposes in ann_test.cpp). //---------------------------------------------------------------------- ANNbruteForce::ANNbruteForce( // constructor from point array ANNpointArray pa, // point array int n, // number of points int dd) // dimension { dim = dd; n_pts = n; pts = pa; } ANNbruteForce::~ANNbruteForce() { } // destructor (empty) void ANNbruteForce::annkSearch( // approx k near neighbor search ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor indices (returned) ANNdistArray dd, // dist to near neighbors (returned) double eps) // error bound (ignored) { ANNmin_k mk(k); // construct a k-limited priority queue int i; if (k > n_pts) { // too many near neighbors? annError("Requesting more near neighbors than data points", ANNabort); } // run every point through queue for (i = 0; i < n_pts; i++) { // compute distance to point ANNdist sqDist = annDist(dim, pts[i], q); if (ANN_ALLOW_SELF_MATCH || sqDist != 0) mk.insert(sqDist, i); } for (i = 0; i < k; i++) { // extract the k closest points dd[i] = mk.ith_smallest_key(i); nn_idx[i] = mk.ith_smallest_info(i); } } int ANNbruteForce::annkFRSearch( // approx fixed-radius kNN search ANNpoint q, // query point ANNdist sqRad, // squared radius int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor array (returned) ANNdistArray dd, // dist to near neighbors (returned) double eps) // error bound { ANNmin_k mk(k); // construct a k-limited priority queue int i; int pts_in_range = 0; // number of points in query range // run every point through queue for (i = 0; i < n_pts; i++) { // compute distance to point ANNdist sqDist = annDist(dim, pts[i], q); if (sqDist <= sqRad && // within radius bound (ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match mk.insert(sqDist, i); pts_in_range++; } } for (i = 0; i < k; i++) { // extract the k closest points if (dd != NULL) dd[i] = mk.ith_smallest_key(i); if (nn_idx != NULL) nn_idx[i] = mk.ith_smallest_info(i); } return pts_in_range; } mldemos-0.4.3/_3rdParty/ANN/kd_dump.cpp000066400000000000000000000413351172143270300175760ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_dump.cc // Programmer: David Mount // Description: Dump and Load for kd- and bd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Moved dump out of kd_tree.cc into this file. // Added kd-tree load constructor. //---------------------------------------------------------------------- // This file contains routines for dumping kd-trees and bd-trees and // reloading them. (It is an abuse of policy to include both kd- and // bd-tree routines in the same file, sorry. There should be no problem // in deleting the bd- versions of the routines if they are not // desired.) //---------------------------------------------------------------------- #include "kd_tree.h" // kd-tree declarations #include "bd_tree.h" // bd-tree declarations using namespace std; // make std:: available //---------------------------------------------------------------------- // Constants //---------------------------------------------------------------------- const int STRING_LEN = 500; // maximum string length const double EPSILON = 1E-5; // small number for float comparison enum ANNtreeType {KD_TREE, BD_TREE}; // tree types (used in loading) //---------------------------------------------------------------------- // Procedure declarations //---------------------------------------------------------------------- static ANNkd_ptr annReadDump( // read dump file istream &in, // input stream ANNtreeType tree_type, // type of tree expected ANNpointArray &the_pts, // new points (if applic) ANNidxArray &the_pidx, // point indices (returned) int &the_dim, // dimension (returned) int &the_n_pts, // number of points (returned) int &the_bkt_size, // bucket size (returned) ANNpoint &the_bnd_box_lo, // low bounding point ANNpoint &the_bnd_box_hi); // high bounding point static ANNkd_ptr annReadTree( // read tree-part of dump file istream &in, // input stream ANNtreeType tree_type, // type of tree expected ANNidxArray the_pidx, // point indices (modified) int &next_idx); // next index (modified) //---------------------------------------------------------------------- // ANN kd- and bd-tree Dump Format // The dump file begins with a header containing the version of // ANN, an optional section containing the points, followed by // a description of the tree. The tree is printed in preorder. // // Format: // #ANN [END_OF_LINE] // points (point coordinates: this is optional) // 0 ... (point indices and coordinates) // 1 ... // ... // tree // ... (lower end of bounding box) // ... (upper end of bounding box) // If the tree is null, then a single line "null" is // output. Otherwise the nodes of the tree are printed // one per line in preorder. Leaves and splitting nodes // have the following formats: // Leaf node: // leaf ... // Splitting nodes: // split // // For bd-trees: // // Shrinking nodes: // shrink // // // ... (repeated n_bnds times) //---------------------------------------------------------------------- void ANNkd_tree::Dump( // dump entire tree ANNbool with_pts, // print points as well? ostream &out) // output stream { out << "#ANN " << ANNversion << "\n"; out.precision(ANNcoordPrec); // use full precision in dumping if (with_pts) { // print point coordinates out << "points " << dim << " " << n_pts << "\n"; for (int i = 0; i < n_pts; i++) { out << i << " "; annPrintPt(pts[i], dim, out); out << "\n"; } } out << "tree " // print tree elements << dim << " " << n_pts << " " << bkt_size << "\n"; annPrintPt(bnd_box_lo, dim, out); // print lower bound out << "\n"; annPrintPt(bnd_box_hi, dim, out); // print upper bound out << "\n"; if (root == NULL) // empty tree? out << "null\n"; else { root->dump(out); // invoke printing at root } out.precision(0); // restore default precision } void ANNkd_split::dump( // dump a splitting node ostream &out) // output stream { out << "split " << cut_dim << " " << cut_val << " "; out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n"; child[ANN_LO]->dump(out); // print low child child[ANN_HI]->dump(out); // print high child } void ANNkd_leaf::dump( // dump a leaf node ostream &out) // output stream { if (this == KD_TRIVIAL) { // canonical trivial leaf node out << "leaf 0\n"; // leaf no points } else{ out << "leaf " << n_pts; for (int j = 0; j < n_pts; j++) { out << " " << bkt[j]; } out << "\n"; } } void ANNbd_shrink::dump( // dump a shrinking node ostream &out) // output stream { out << "shrink " << n_bnds << "\n"; for (int j = 0; j < n_bnds; j++) { out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n"; } child[ANN_IN]->dump(out); // print in-child child[ANN_OUT]->dump(out); // print out-child } //---------------------------------------------------------------------- // Load kd-tree from dump file // This rebuilds a kd-tree which was dumped to a file. The dump // file contains all the basic tree information according to a // preorder traversal. We assume that the dump file also contains // point data. (This is to guarantee the consistency of the tree.) // If not, then an error is generated. // // Indirectly, this procedure allocates space for points, point // indices, all nodes in the tree, and the bounding box for the // tree. When the tree is destroyed, all but the points are // deallocated. // // This routine calls annReadDump to do all the work. //---------------------------------------------------------------------- ANNkd_tree::ANNkd_tree( // build from dump file istream &in) // input stream for dump file { int the_dim; // local dimension int the_n_pts; // local number of points int the_bkt_size; // local number of points ANNpoint the_bnd_box_lo; // low bounding point ANNpoint the_bnd_box_hi; // high bounding point ANNpointArray the_pts; // point storage ANNidxArray the_pidx; // point index storage ANNkd_ptr the_root; // root of the tree the_root = annReadDump( // read the dump file in, // input stream KD_TREE, // expecting a kd-tree the_pts, // point array (returned) the_pidx, // point indices (returned) the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) // create a skeletal tree SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); bnd_box_lo = the_bnd_box_lo; bnd_box_hi = the_bnd_box_hi; root = the_root; // set the root } ANNbd_tree::ANNbd_tree( // build bd-tree from dump file istream &in) : ANNkd_tree() // input stream for dump file { int the_dim; // local dimension int the_n_pts; // local number of points int the_bkt_size; // local number of points ANNpoint the_bnd_box_lo; // low bounding point ANNpoint the_bnd_box_hi; // high bounding point ANNpointArray the_pts; // point storage ANNidxArray the_pidx; // point index storage ANNkd_ptr the_root; // root of the tree the_root = annReadDump( // read the dump file in, // input stream BD_TREE, // expecting a bd-tree the_pts, // point array (returned) the_pidx, // point indices (returned) the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) // create a skeletal tree SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); bnd_box_lo = the_bnd_box_lo; bnd_box_hi = the_bnd_box_hi; root = the_root; // set the root } //---------------------------------------------------------------------- // annReadDump - read a dump file // // This procedure reads a dump file, constructs a kd-tree // and returns all the essential information needed to actually // construct the tree. Because this procedure is used for // constructing both kd-trees and bd-trees, the second argument // is used to indicate which type of tree we are expecting. //---------------------------------------------------------------------- static ANNkd_ptr annReadDump( istream &in, // input stream ANNtreeType tree_type, // type of tree expected ANNpointArray &the_pts, // new points (returned) ANNidxArray &the_pidx, // point indices (returned) int &the_dim, // dimension (returned) int &the_n_pts, // number of points (returned) int &the_bkt_size, // bucket size (returned) ANNpoint &the_bnd_box_lo, // low bounding point (ret'd) ANNpoint &the_bnd_box_hi) // high bounding point (ret'd) { int j; char str[STRING_LEN]; // storage for string char version[STRING_LEN]; // ANN version number ANNkd_ptr the_root = NULL; //------------------------------------------------------------------ // Input file header //------------------------------------------------------------------ in >> str; // input header if (strcmp(str, "#ANN") != 0) { // incorrect header annError("Incorrect header for dump file", ANNabort); } in.getline(version, STRING_LEN); // get version (ignore) //------------------------------------------------------------------ // Input the points // An array the_pts is allocated and points are read from // the dump file. //------------------------------------------------------------------ in >> str; // get major heading if (strcmp(str, "points") == 0) { // points section in >> the_dim; // input dimension in >> the_n_pts; // number of points // allocate point storage the_pts = annAllocPts(the_n_pts, the_dim); for (int i = 0; i < the_n_pts; i++) { // input point coordinates ANNidx idx; // point index in >> idx; // input point index if (idx < 0 || idx >= the_n_pts) { annError("Point index is out of range", ANNabort); } for (j = 0; j < the_dim; j++) { in >> the_pts[idx][j]; // read point coordinates } } in >> str; // get next major heading } else { // no points were input annError("Points must be supplied in the dump file", ANNabort); } //------------------------------------------------------------------ // Input the tree // After the basic header information, we invoke annReadTree // to do all the heavy work. We create our own array of // point indices (so we can pass them to annReadTree()) // but we do not deallocate them. They will be deallocated // when the tree is destroyed. //------------------------------------------------------------------ if (strcmp(str, "tree") == 0) { // tree section in >> the_dim; // read dimension in >> the_n_pts; // number of points in >> the_bkt_size; // bucket size the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts the_bnd_box_hi = annAllocPt(the_dim); for (j = 0; j < the_dim; j++) { // read bounding box low in >> the_bnd_box_lo[j]; } for (j = 0; j < the_dim; j++) { // read bounding box low in >> the_bnd_box_hi[j]; } the_pidx = new ANNidx[the_n_pts]; // allocate point index array int next_idx = 0; // number of indices filled // read the tree and indices the_root = annReadTree(in, tree_type, the_pidx, next_idx); if (next_idx != the_n_pts) { // didn't see all the points? annError("Didn't see as many points as expected", ANNwarn); } } else { annError("Illegal dump format. Expecting section heading", ANNabort); } return the_root; } //---------------------------------------------------------------------- // annReadTree - input tree and return pointer // // annReadTree reads in a node of the tree, makes any recursive // calls as needed to input the children of this node (if internal). // It returns a pointer to the node that was created. An array // of point indices is given along with a pointer to the next // available location in the array. As leaves are read, their // point indices are stored here, and the point buckets point // to the first entry in the array. // // Recall that these are the formats. The tree is given in // preorder. // // Leaf node: // leaf ... // Splitting nodes: // split // // For bd-trees: // // Shrinking nodes: // shrink // // // ... (repeated n_bnds times) //---------------------------------------------------------------------- static ANNkd_ptr annReadTree( istream &in, // input stream ANNtreeType tree_type, // type of tree expected ANNidxArray the_pidx, // point indices (modified) int &next_idx) // next index (modified) { char tag[STRING_LEN]; // tag (leaf, split, shrink) int n_pts; // number of points in leaf int cd; // cut dimension ANNcoord cv; // cut value ANNcoord lb; // low bound ANNcoord hb; // high bound int n_bnds; // number of bounding sides int sd; // which side in >> tag; // input node tag if (strcmp(tag, "null") == 0) { // null tree return NULL; } //------------------------------------------------------------------ // Read a leaf //------------------------------------------------------------------ if (strcmp(tag, "leaf") == 0) { // leaf node in >> n_pts; // input number of points int old_idx = next_idx; // save next_idx if (n_pts == 0) { // trivial leaf return KD_TRIVIAL; } else { for (int i = 0; i < n_pts; i++) { // input point indices in >> the_pidx[next_idx++]; // store in array of indices } } return new ANNkd_leaf(n_pts, &the_pidx[old_idx]); } //------------------------------------------------------------------ // Read a splitting node //------------------------------------------------------------------ else if (strcmp(tag, "split") == 0) { // splitting node in >> cd >> cv >> lb >> hb; // read low and high subtrees ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx); ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx); // create new node and return return new ANNkd_split(cd, cv, lb, hb, lc, hc); } //------------------------------------------------------------------ // Read a shrinking node (bd-tree only) //------------------------------------------------------------------ else if (strcmp(tag, "shrink") == 0) { // shrinking node if (tree_type != BD_TREE) { annError("Shrinking node not allowed in kd-tree", ANNabort); } in >> n_bnds; // number of bounding sides // allocate bounds array ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds]; for (int i = 0; i < n_bnds; i++) { in >> cd >> cv >> sd; // input bounding halfspace // copy to array bds[i] = ANNorthHalfSpace(cd, cv, sd); } // read inner and outer subtrees ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx); ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx); // create new node and return return new ANNbd_shrink(n_bnds, bds, ic, oc); } else { annError("Illegal node type in dump file", ANNabort); exit(0); // to keep the compiler happy } } mldemos-0.4.3/_3rdParty/ANN/kd_fix_rad_search.cpp000066400000000000000000000214511172143270300215670ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_fix_rad_search.cpp // Programmer: Sunil Arya and David Mount // Description: Standard kd-tree fixed-radius kNN search // Last modified: 05/03/05 (Version 1.1) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 1.1 05/03/05 // Initial release //---------------------------------------------------------------------- #include "kd_fix_rad_search.h" // kd fixed-radius search decls //---------------------------------------------------------------------- // Approximate fixed-radius k nearest neighbor search // The squared radius is provided, and this procedure finds the // k nearest neighbors within the radius, and returns the total // number of points lying within the radius. // // The method used for searching the kd-tree is a variation of the // nearest neighbor search used in kd_search.cpp, except that the // radius of the search ball is known. We refer the reader to that // file for the explanation of the recursive search procedure. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // To keep argument lists short, a number of global variables // are maintained which are common to all the recursive calls. // These are given below. //---------------------------------------------------------------------- int ANNkdFRDim; // dimension of space ANNpoint ANNkdFRQ; // query point ANNdist ANNkdFRSqRad; // squared radius search bound double ANNkdFRMaxErr; // max tolerable squared error ANNpointArray ANNkdFRPts; // the points ANNmin_k* ANNkdFRPointMK; // set of k closest points int ANNkdFRPtsVisited; // total points visited int ANNkdFRPtsInRange; // number of points in the range //---------------------------------------------------------------------- // annkFRSearch - fixed radius search for k nearest neighbors //---------------------------------------------------------------------- int ANNkd_tree::annkFRSearch( ANNpoint q, // the query point ANNdist sqRad, // squared radius search bound int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor indices (returned) ANNdistArray dd, // the approximate nearest neighbor double eps) // the error bound { ANNkdFRDim = dim; // copy arguments to static equivs ANNkdFRQ = q; ANNkdFRSqRad = sqRad; ANNkdFRPts = pts; ANNkdFRPtsVisited = 0; // initialize count of points visited ANNkdFRPtsInRange = 0; // ...and points in the range switch(ANN::MetricType) { case ANN_METRIC0: ANNkdFRMaxErr = ANN_POW0(1.0 + eps); break; case ANN_METRIC1: ANNkdFRMaxErr = ANN_POW1(1.0 + eps); break; case ANN_METRIC2: ANNkdFRMaxErr = ANN_POW(1.0 + eps); break; case ANN_METRICP: ANNkdFRMaxErr = ANN_POWp(1.0 + eps); break; } ANN_FLOP(2) // increment floating op count ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points // search starting at the root root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); for (int i = 0; i < k; i++) { // extract the k-th closest points if (dd != NULL) dd[i] = ANNkdFRPointMK->ith_smallest_key(i); if (nn_idx != NULL) nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i); } delete ANNkdFRPointMK; // deallocate closest point set return ANNkdFRPtsInRange; // return final point count } //---------------------------------------------------------------------- // kd_split::ann_FR_search - search a splitting node // Note: This routine is similar in structure to the standard kNN // search. It visits the subtree that is closer to the query point // first. For fixed-radius search, there is no benefit in visiting // one subtree before the other, but we maintain the same basic // code structure for the sake of uniformity. //---------------------------------------------------------------------- void ANNkd_split::ann_FR_search(ANNdist box_dist) { // check dist calc term condition if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return; // distance to cutting plane ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val; if (cut_diff < 0) { // left of cutting plane child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: box_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: box_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: box_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: box_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } // visit further child if in range if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) child[ANN_HI]->ann_FR_search(box_dist); } else { // right of cutting plane child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: box_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: box_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: box_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: box_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } // visit further child if close enough if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) child[ANN_LO]->ann_FR_search(box_dist); } ANN_FLOP(13) // increment floating ops ANN_SPL(1) // one more splitting node visited } //---------------------------------------------------------------------- // kd_leaf::ann_FR_search - search points in a leaf node // Note: The unreadability of this code is the result of // some fine tuning to replace indexing by pointer operations. //---------------------------------------------------------------------- void ANNkd_leaf::ann_FR_search(ANNdist box_dist) { register ANNdist dist; // distance to data point register ANNcoord* pp; // data coordinate pointer register ANNcoord* qq; // query coordinate pointer register ANNcoord t; register int d; for (int i = 0; i < n_pts; i++) { // check points in bucket pp = ANNkdFRPts[bkt[i]]; // first coord of next data point qq = ANNkdFRQ; // first coord of query point dist = 0; for(d = 0; d < ANNkdFRDim; d++) { ANN_COORD(1) // one more coordinate hit ANN_FLOP(5) // increment floating ops t = *(qq++) - *(pp++); // compute length and adv coordinate // exceeds dist to k-th smallest? switch(ANN::MetricType) { case ANN_METRIC0: dist = ANN_SUM0(dist, ANN_POW0(t)); break; case ANN_METRIC1: dist = ANN_SUM1(dist, ANN_POW1(t)); break; case ANN_METRIC2: dist = ANN_SUM(dist, ANN_POW(t)); break; case ANN_METRICP: dist = ANN_SUMp(dist, ANN_POWp(t)); break; } if( dist > ANNkdFRSqRad) { break; } } if (d >= ANNkdFRDim && // among the k best? (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem // add it to the list ANNkdFRPointMK->insert(dist, bkt[i]); ANNkdFRPtsInRange++; // increment point count } } ANN_LEAF(1) // one more leaf node visited ANN_PTS(n_pts) // increment points visited ANNkdFRPtsVisited += n_pts; // increment number of points visited } mldemos-0.4.3/_3rdParty/ANN/kd_fix_rad_search.h000066400000000000000000000034621172143270300212360ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_fix_rad_search.h // Programmer: Sunil Arya and David Mount // Description: Standard kd-tree fixed-radius kNN search // Last modified: 05/03/05 (Version 1.1) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 1.1 05/03/05 // Initial release //---------------------------------------------------------------------- #ifndef ANN_kd_fix_rad_search_H #define ANN_kd_fix_rad_search_H #include "kd_tree.h" // kd-tree declarations #include "kd_util.h" // kd-tree utilities #include "pr_queue_k.h" // k-element priority queue #include // performance evaluation //---------------------------------------------------------------------- // Global variables // These are active for the life of each call to // annRangeSearch(). They are set to save the number of // variables that need to be passed among the various search // procedures. //---------------------------------------------------------------------- extern ANNpoint ANNkdFRQ; // query point (static copy) #endif mldemos-0.4.3/_3rdParty/ANN/kd_pr_search.cpp000066400000000000000000000245321172143270300205770ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_pr_search.cpp // Programmer: Sunil Arya and David Mount // Description: Priority search for kd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #include "kd_pr_search.h" // kd priority search declarations //---------------------------------------------------------------------- // Approximate nearest neighbor searching by priority search. // The kd-tree is searched for an approximate nearest neighbor. // The point is returned through one of the arguments, and the // distance returned is the SQUARED distance to this point. // // The method used for searching the kd-tree is called priority // search. (It is described in Arya and Mount, ``Algorithms for // fast vector quantization,'' Proc. of DCC '93: Data Compression // Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, // 381--390.) // // The cell of the kd-tree containing the query point is located, // and cells are visited in increasing order of distance from the // query point. This is done by placing each subtree which has // NOT been visited in a priority queue, according to the closest // distance of the corresponding enclosing rectangle from the // query point. The search stops when the distance to the nearest // remaining rectangle exceeds the distance to the nearest point // seen by a factor of more than 1/(1+eps). (Implying that any // point found subsequently in the search cannot be closer by more // than this factor.) // // The main entry point is annkPriSearch() which sets things up and // then call the recursive routine ann_pri_search(). This is a // recursive routine which performs the processing for one node in // the kd-tree. There are two versions of this virtual procedure, // one for splitting nodes and one for leaves. When a splitting node // is visited, we determine which child to continue the search on // (the closer one), and insert the other child into the priority // queue. When a leaf is visited, we compute the distances to the // points in the buckets, and update information on the closest // points. // // Some trickery is used to incrementally update the distance from // a kd-tree rectangle to the query point. This comes about from // the fact that which each successive split, only one component // (along the dimension that is split) of the squared distance to // the child rectangle is different from the squared distance to // the parent rectangle. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // To keep argument lists short, a number of global variables // are maintained which are common to all the recursive calls. // These are given below. //---------------------------------------------------------------------- double ANNprEps; // the error bound int ANNprDim; // dimension of space ANNpoint ANNprQ; // query point double ANNprMaxErr; // max tolerable squared error ANNpointArray ANNprPts; // the points ANNpr_queue *ANNprBoxPQ; // priority queue for boxes ANNmin_k *ANNprPointMK; // set of k closest points //---------------------------------------------------------------------- // annkPriSearch - priority search for k nearest neighbors //---------------------------------------------------------------------- void ANNkd_tree::annkPriSearch( ANNpoint q, // query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor indices (returned) ANNdistArray dd, // dist to near neighbors (returned) double eps) // error bound (ignored) { // max tolerable squared error switch(ANN::MetricType) { case ANN_METRIC0: ANNprMaxErr = ANN_POW0(1.0 + eps); break; case ANN_METRIC1: ANNprMaxErr = ANN_POW1(1.0 + eps); break; case ANN_METRIC2: ANNprMaxErr = ANN_POW(1.0 + eps); break; case ANN_METRICP: ANNprMaxErr = ANN_POWp(1.0 + eps); break; } ANN_FLOP(2) // increment floating ops ANNprDim = dim; // copy arguments to static equivs ANNprQ = q; ANNprPts = pts; ANNptsVisited = 0; // initialize count of points visited ANNprPointMK = new ANNmin_k(k); // create set for closest k points // distance to root box ANNdist box_dist = annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim); ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue while (ANNprBoxPQ->non_empty() && (!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) { ANNkd_ptr np; // next box from prior queue // extract closest box from queue ANNprBoxPQ->extr_min(box_dist, (void *&) np); ANN_FLOP(2) // increment floating ops if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key()) break; np->ann_pri_search(box_dist); // search this subtree. } for (int i = 0; i < k; i++) { // extract the k-th closest points dd[i] = ANNprPointMK->ith_smallest_key(i); nn_idx[i] = ANNprPointMK->ith_smallest_info(i); } delete ANNprPointMK; // deallocate closest point set delete ANNprBoxPQ; // deallocate priority queue } //---------------------------------------------------------------------- // kd_split::ann_pri_search - search a splitting node //---------------------------------------------------------------------- void ANNkd_split::ann_pri_search(ANNdist box_dist) { ANNdist new_dist; // distance to child visited later // distance to cutting plane ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val; if (cut_diff < 0) { // left of cutting plane ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: new_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: new_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: new_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: new_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial ANNprBoxPQ->insert(new_dist, child[ANN_HI]); // continue with closer child child[ANN_LO]->ann_pri_search(box_dist); } else { // right of cutting plane ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: new_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: new_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: new_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: new_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial ANNprBoxPQ->insert(new_dist, child[ANN_LO]); // continue with closer child child[ANN_HI]->ann_pri_search(box_dist); } ANN_SPL(1) // one more splitting node visited ANN_FLOP(8) // increment floating ops } //---------------------------------------------------------------------- // kd_leaf::ann_pri_search - search points in a leaf node // // This is virtually identical to the ann_search for standard search. //---------------------------------------------------------------------- void ANNkd_leaf::ann_pri_search(ANNdist box_dist) { register ANNdist dist; // distance to data point register ANNcoord* pp; // data coordinate pointer register ANNcoord* qq; // query coordinate pointer register ANNdist min_dist; // distance to k-th closest point register ANNcoord t; register int d; min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far for (int i = 0; i < n_pts; i++) { // check points in bucket pp = ANNprPts[bkt[i]]; // first coord of next data point qq = ANNprQ; // first coord of query point dist = 0; for(d = 0; d < ANNprDim; d++) { ANN_COORD(1) // one more coordinate hit ANN_FLOP(4) // increment floating ops t = *(qq++) - *(pp++); // compute length and adv coordinate // exceeds dist to k-th smallest? switch(ANN::MetricType) { case ANN_METRIC0: dist = ANN_SUM0(dist, ANN_POW0(t)); break; case ANN_METRIC1: dist = ANN_SUM1(dist, ANN_POW1(t)); break; case ANN_METRIC2: dist = ANN_SUM(dist, ANN_POW(t)); break; case ANN_METRICP: dist = ANN_SUMp(dist, ANN_POWp(t)); break; } if( dist > min_dist) break; } if (d >= ANNprDim && // among the k best? (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem // add it to the list ANNprPointMK->insert(dist, bkt[i]); min_dist = ANNprPointMK->max_key(); } } ANN_LEAF(1) // one more leaf node visited ANN_PTS(n_pts) // increment points visited ANNptsVisited += n_pts; // increment number of points visited } mldemos-0.4.3/_3rdParty/ANN/kd_pr_search.h000066400000000000000000000040341172143270300202370ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_pr_search.h // Programmer: Sunil Arya and David Mount // Description: Priority kd-tree search // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef ANN_kd_pr_search_H #define ANN_kd_pr_search_H #include "kd_tree.h" // kd-tree declarations #include "kd_util.h" // kd-tree utilities #include "pr_queue.h" // priority queue declarations #include "pr_queue_k.h" // k-element priority queue #include // performance evaluation //---------------------------------------------------------------------- // Global variables // Active for the life of each call to Appx_Near_Neigh() or // Appx_k_Near_Neigh(). //---------------------------------------------------------------------- extern double ANNprEps; // the error bound extern int ANNprDim; // dimension of space extern ANNpoint ANNprQ; // query point extern double ANNprMaxErr; // max tolerable squared error extern ANNpointArray ANNprPts; // the points extern ANNpr_queue *ANNprBoxPQ; // priority queue for boxes extern ANNmin_k *ANNprPointMK; // set of k closest points #endif mldemos-0.4.3/_3rdParty/ANN/kd_search.cpp000066400000000000000000000241571172143270300201010ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_search.cpp // Programmer: Sunil Arya and David Mount // Description: Standard kd-tree search // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Changed names LO, HI to ANN_LO, ANN_HI //---------------------------------------------------------------------- #include "kd_search.h" // kd-search declarations //---------------------------------------------------------------------- // Approximate nearest neighbor searching by kd-tree search // The kd-tree is searched for an approximate nearest neighbor. // The point is returned through one of the arguments, and the // distance returned is the squared distance to this point. // // The method used for searching the kd-tree is an approximate // adaptation of the search algorithm described by Friedman, // Bentley, and Finkel, ``An algorithm for finding best matches // in logarithmic expected time,'' ACM Transactions on Mathematical // Software, 3(3):209-226, 1977). // // The algorithm operates recursively. When first encountering a // node of the kd-tree we first visit the child which is closest to // the query point. On return, we decide whether we want to visit // the other child. If the box containing the other child exceeds // 1/(1+eps) times the current best distance, then we skip it (since // any point found in this child cannot be closer to the query point // by more than this factor.) Otherwise, we visit it recursively. // The distance between a box and the query point is computed exactly // (not approximated as is often done in kd-tree), using incremental // distance updates, as described by Arya and Mount in ``Algorithms // for fast vector quantization,'' Proc. of DCC '93: Data Compression // Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, // 381-390. // // The main entry points is annkSearch() which sets things up and // then call the recursive routine ann_search(). This is a recursive // routine which performs the processing for one node in the kd-tree. // There are two versions of this virtual procedure, one for splitting // nodes and one for leaves. When a splitting node is visited, we // determine which child to visit first (the closer one), and visit // the other child on return. When a leaf is visited, we compute // the distances to the points in the buckets, and update information // on the closest points. // // Some trickery is used to incrementally update the distance from // a kd-tree rectangle to the query point. This comes about from // the fact that which each successive split, only one component // (along the dimension that is split) of the squared distance to // the child rectangle is different from the squared distance to // the parent rectangle. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // To keep argument lists short, a number of global variables // are maintained which are common to all the recursive calls. // These are given below. //---------------------------------------------------------------------- int ANNkdDim; // dimension of space ANNpoint ANNkdQ; // query point double ANNkdMaxErr; // max tolerable squared error ANNpointArray ANNkdPts; // the points ANNmin_k *ANNkdPointMK; // set of k closest points //---------------------------------------------------------------------- // annkSearch - search for the k nearest neighbors //---------------------------------------------------------------------- void ANNkd_tree::annkSearch( ANNpoint q, // the query point int k, // number of near neighbors to return ANNidxArray nn_idx, // nearest neighbor indices (returned) ANNdistArray dd, // the approximate nearest neighbor double eps) // the error bound { ANNkdDim = dim; // copy arguments to static equivs ANNkdQ = q; ANNkdPts = pts; ANNptsVisited = 0; // initialize count of points visited if (k > n_pts) { // too many near neighbors? annError("Requesting more near neighbors than data points", ANNabort); } switch(ANN::MetricType) { case ANN_METRIC0: ANNkdMaxErr = ANN_POW0(1.0 + eps); break; case ANN_METRIC1: ANNkdMaxErr = ANN_POW1(1.0 + eps); break; case ANN_METRIC2: ANNkdMaxErr = ANN_POW(1.0 + eps); break; case ANN_METRICP: ANNkdMaxErr = ANN_POWp(1.0 + eps); break; } ANN_FLOP(2) // increment floating op count ANNkdPointMK = new ANNmin_k(k); // create set for closest k points // search starting at the root root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); for (int i = 0; i < k; i++) { // extract the k-th closest points dd[i] = ANNkdPointMK->ith_smallest_key(i); nn_idx[i] = ANNkdPointMK->ith_smallest_info(i); } delete ANNkdPointMK; // deallocate closest point set } //---------------------------------------------------------------------- // kd_split::ann_search - search a splitting node //---------------------------------------------------------------------- void ANNkd_split::ann_search(ANNdist box_dist) { // check dist calc term condition if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; // distance to cutting plane ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val; if (cut_diff < 0) { // left of cutting plane child[ANN_LO]->ann_search(box_dist);// visit closer child first ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: box_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: box_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: box_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: box_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } // visit further child if close enough if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) child[ANN_HI]->ann_search(box_dist); } else { // right of cutting plane child[ANN_HI]->ann_search(box_dist);// visit closer child first ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI]; if (box_diff < 0) // within bounds - ignore box_diff = 0; // distance to further box switch(ANN::MetricType) { case ANN_METRIC0: box_dist = (ANNdist) ANN_SUM0(box_dist, ANN_DIFF0(ANN_POW0(box_diff), ANN_POW0(cut_diff))); break; case ANN_METRIC1: box_dist = (ANNdist) ANN_SUM1(box_dist, ANN_DIFF1(ANN_POW1(box_diff), ANN_POW1(cut_diff))); break; case ANN_METRIC2: box_dist = (ANNdist) ANN_SUM(box_dist, ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); break; case ANN_METRICP: box_dist = (ANNdist) ANN_SUMp(box_dist, ANN_DIFFp(ANN_POWp(box_diff), ANN_POWp(cut_diff))); break; } // visit further child if close enough if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) child[ANN_LO]->ann_search(box_dist); } ANN_FLOP(10) // increment floating ops ANN_SPL(1) // one more splitting node visited } //---------------------------------------------------------------------- // kd_leaf::ann_search - search points in a leaf node // Note: The unreadability of this code is the result of // some fine tuning to replace indexing by pointer operations. //---------------------------------------------------------------------- void ANNkd_leaf::ann_search(ANNdist box_dist) { register ANNdist dist; // distance to data point register ANNcoord* pp; // data coordinate pointer register ANNcoord* qq; // query coordinate pointer register ANNdist min_dist; // distance to k-th closest point register ANNcoord t; register int d; min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far for (int i = 0; i < n_pts; i++) { // check points in bucket pp = ANNkdPts[bkt[i]]; // first coord of next data point qq = ANNkdQ; // first coord of query point dist = 0; for(d = 0; d < ANNkdDim; d++) { ANN_COORD(1) // one more coordinate hit ANN_FLOP(4) // increment floating ops t = *(qq++) - *(pp++); // compute length and adv coordinate // exceeds dist to k-th smallest? switch(ANN::MetricType) { case ANN_METRIC0: dist = ANN_SUM0(dist, ANN_POW0(t)); break; case ANN_METRIC1: dist = ANN_SUM1(dist, ANN_POW1(t)); break; case ANN_METRIC2: dist = ANN_SUM(dist, ANN_POW(t)); break; case ANN_METRICP: dist = ANN_SUMp(dist, ANN_POWp(t)); break; } if( dist > min_dist) { break; } } if (d >= ANNkdDim && // among the k best? (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem // add it to the list ANNkdPointMK->insert(dist, bkt[i]); min_dist = ANNkdPointMK->max_key(); } } ANN_LEAF(1) // one more leaf node visited ANN_PTS(n_pts) // increment points visited ANNptsVisited += n_pts; // increment number of points visited } mldemos-0.4.3/_3rdParty/ANN/kd_search.h000066400000000000000000000040611172143270300175360ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_search.h // Programmer: Sunil Arya and David Mount // Description: Standard kd-tree search // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef ANN_kd_search_H #define ANN_kd_search_H #include "kd_tree.h" // kd-tree declarations #include "kd_util.h" // kd-tree utilities #include "pr_queue_k.h" // k-element priority queue #include // performance evaluation //---------------------------------------------------------------------- // More global variables // These are active for the life of each call to annkSearch(). They // are set to save the number of variables that need to be passed // among the various search procedures. //---------------------------------------------------------------------- extern int ANNkdDim; // dimension of space (static copy) extern ANNpoint ANNkdQ; // query point (static copy) extern double ANNkdMaxErr; // max tolerable squared error extern ANNpointArray ANNkdPts; // the points (static copy) extern ANNmin_k *ANNkdPointMK; // set of k closest points extern int ANNptsVisited; // number of points visited #endif mldemos-0.4.3/_3rdParty/ANN/kd_split.cpp000066400000000000000000000416321172143270300177640ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_split.cpp // Programmer: Sunil Arya and David Mount // Description: Methods for splitting kd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 //---------------------------------------------------------------------- #include "kd_tree.h" // kd-tree definitions #include "kd_util.h" // kd-tree utilities #include "kd_split.h" // splitting functions //---------------------------------------------------------------------- // Constants //---------------------------------------------------------------------- const double ERR = 0.001; // a small value const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio // in fair split. Must be >= 2. //---------------------------------------------------------------------- // kd_split - Bentley's standard splitting routine for kd-trees // Find the dimension of the greatest spread, and split // just before the median point along this dimension. //---------------------------------------------------------------------- void kd_split( ANNpointArray pa, // point array (permuted on return) ANNidxArray pidx, // point indices const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo) // num of points on low side (returned) { // find dimension of maximum spread cut_dim = annMaxSpread(pa, pidx, n, dim); n_lo = n/2; // median rank // split about median annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); } //---------------------------------------------------------------------- // midpt_split - midpoint splitting rule for box-decomposition trees // // This is the simplest splitting rule that guarantees boxes // of bounded aspect ratio. It simply cuts the box with the // longest side through its midpoint. If there are ties, it // selects the dimension with the maximum point spread. // // WARNING: This routine (while simple) doesn't seem to work // well in practice in high dimensions, because it tends to // generate a large number of trivial and/or unbalanced splits. // Either kd_split(), sl_midpt_split(), or fair_split() are // recommended, instead. //---------------------------------------------------------------------- void midpt_split( ANNpointArray pa, // point array ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo) // num of points on low side (returned) { int d; ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; for (d = 1; d < dim; d++) { // find length of longest box side ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (length > max_length) { max_length = length; } } ANNcoord max_spread = -1; // find long side with most spread for (d = 0; d < dim; d++) { // is it among longest? if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { // compute its spread ANNcoord spr = annSpread(pa, pidx, n, d); if (spr > max_spread) { // is it max so far? max_spread = spr; cut_dim = d; } } } // split along cut_dim at midpoint cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2; // permute points accordingly int br1, br2; annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); //------------------------------------------------------------------ // On return: pa[0..br1-1] < cut_val // pa[br1..br2-1] == cut_val // pa[br2..n-1] > cut_val // // We can set n_lo to any value in the range [br1..br2]. // We choose split so that points are most evenly divided. //------------------------------------------------------------------ if (br1 > n/2) n_lo = br1; else if (br2 < n/2) n_lo = br2; else n_lo = n/2; } //---------------------------------------------------------------------- // sl_midpt_split - sliding midpoint splitting rule // // This is a modification of midpt_split, which has the nonsensical // name "sliding midpoint". The idea is that we try to use the // midpoint rule, by bisecting the longest side. If there are // ties, the dimension with the maximum spread is selected. If, // however, the midpoint split produces a trivial split (no points // on one side of the splitting plane) then we slide the splitting // (maintaining its orientation) until it produces a nontrivial // split. For example, if the splitting plane is along the x-axis, // and all the data points have x-coordinate less than the x-bisector, // then the split is taken along the maximum x-coordinate of the // data points. // // Intuitively, this rule cannot generate trivial splits, and // hence avoids midpt_split's tendency to produce trees with // a very large number of nodes. // //---------------------------------------------------------------------- void sl_midpt_split( ANNpointArray pa, // point array ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo) // num of points on low side (returned) { int d; ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; for (d = 1; d < dim; d++) { // find length of longest box side ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (length > max_length) { max_length = length; } } ANNcoord max_spread = -1; // find long side with most spread for (d = 0; d < dim; d++) { // is it among longest? if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { // compute its spread ANNcoord spr = annSpread(pa, pidx, n, d); if (spr > max_spread) { // is it max so far? max_spread = spr; cut_dim = d; } } } // ideal split at midpoint ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2; ANNcoord min, max; annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates if (ideal_cut_val < min) // slide to min or max as needed cut_val = min; else if (ideal_cut_val > max) cut_val = max; else cut_val = ideal_cut_val; // permute points accordingly int br1, br2; annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); //------------------------------------------------------------------ // On return: pa[0..br1-1] < cut_val // pa[br1..br2-1] == cut_val // pa[br2..n-1] > cut_val // // We can set n_lo to any value in the range [br1..br2] to satisfy // the exit conditions of the procedure. // // if ideal_cut_val < min (implying br2 >= 1), // then we select n_lo = 1 (so there is one point on left) and // if ideal_cut_val > max (implying br1 <= n-1), // then we select n_lo = n-1 (so there is one point on right). // Otherwise, we select n_lo as close to n/2 as possible within // [br1..br2]. //------------------------------------------------------------------ if (ideal_cut_val < min) n_lo = 1; else if (ideal_cut_val > max) n_lo = n-1; else if (br1 > n/2) n_lo = br1; else if (br2 < n/2) n_lo = br2; else n_lo = n/2; } //---------------------------------------------------------------------- // fair_split - fair-split splitting rule // // This is a compromise between the kd-tree splitting rule (which // always splits data points at their median) and the midpoint // splitting rule (which always splits a box through its center. // The goal of this procedure is to achieve both nicely balanced // splits, and boxes of bounded aspect ratio. // // A constant FS_ASPECT_RATIO is defined. Given a box, those sides // which can be split so that the ratio of the longest to shortest // side does not exceed ASPECT_RATIO are identified. Among these // sides, we select the one in which the points have the largest // spread. We then split the points in a manner which most evenly // distributes the points on either side of the splitting plane, // subject to maintaining the bound on the ratio of long to short // sides. To determine that the aspect ratio will be preserved, // we determine the longest side (other than this side), and // determine how narrowly we can cut this side, without causing the // aspect ratio bound to be exceeded (small_piece). // // This procedure is more robust than either kd_split or midpt_split, // but is more complicated as well. When point distribution is // extremely skewed, this degenerates to midpt_split (actually // 1/3 point split), and when the points are most evenly distributed, // this degenerates to kd-split. //---------------------------------------------------------------------- void fair_split( ANNpointArray pa, // point array ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo) // num of points on low side (returned) { int d; ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; cut_dim = 0; for (d = 1; d < dim; d++) { // find length of longest box side ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (length > max_length) { max_length = length; cut_dim = d; } } ANNcoord max_spread = 0; // find legal cut with max spread cut_dim = 0; for (d = 0; d < dim; d++) { ANNcoord length = bnds.hi[d] - bnds.lo[d]; // is this side midpoint splitable // without violating aspect ratio? if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { // compute spread along this dim ANNcoord spr = annSpread(pa, pidx, n, d); if (spr > max_spread) { // best spread so far max_spread = spr; cut_dim = d; // this is dimension to cut } } } max_length = 0; // find longest side other than cut_dim for (d = 0; d < dim; d++) { ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (d != cut_dim && length > max_length) max_length = length; } // consider most extreme splits ANNcoord small_piece = max_length / FS_ASPECT_RATIO; ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut int br1, br2; // is median below lo_cut ? if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { cut_val = lo_cut; // cut at lo_cut annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = br1; } // is median above hi_cut? else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { cut_val = hi_cut; // cut at hi_cut annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = br2; } else { // median cut preserves asp ratio n_lo = n/2; // split about median annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); } } //---------------------------------------------------------------------- // sl_fair_split - sliding fair split splitting rule // // Sliding fair split is a splitting rule that combines the // strengths of both fair split with sliding midpoint split. // Fair split tends to produce balanced splits when the points // are roughly uniformly distributed, but it can produce many // trivial splits when points are highly clustered. Sliding // midpoint never produces trivial splits, and shrinks boxes // nicely if points are highly clustered, but it may produce // rather unbalanced splits when points are unclustered but not // quite uniform. // // Sliding fair split is based on the theory that there are two // types of splits that are "good": balanced splits that produce // fat boxes, and unbalanced splits provided the cell with fewer // points is fat. // // This splitting rule operates by first computing the longest // side of the current bounding box. Then it asks which sides // could be split (at the midpoint) and still satisfy the aspect // ratio bound with respect to this side. Among these, it selects // the side with the largest spread (as fair split would). It // then considers the most extreme cuts that would be allowed by // the aspect ratio bound. This is done by dividing the longest // side of the box by the aspect ratio bound. If the median cut // lies between these extreme cuts, then we use the median cut. // If not, then consider the extreme cut that is closer to the // median. If all the points lie to one side of this cut, then // we slide the cut until it hits the first point. This may // violate the aspect ratio bound, but will never generate empty // cells. However the sibling of every such skinny cell is fat, // and hence packing arguments still apply. // //---------------------------------------------------------------------- void sl_fair_split( ANNpointArray pa, // point array ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo) // num of points on low side (returned) { int d; ANNcoord min, max; // min/max coordinates int br1, br2; // split break points ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; cut_dim = 0; for (d = 1; d < dim; d++) { // find length of longest box side ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (length > max_length) { max_length = length; cut_dim = d; } } ANNcoord max_spread = 0; // find legal cut with max spread cut_dim = 0; for (d = 0; d < dim; d++) { ANNcoord length = bnds.hi[d] - bnds.lo[d]; // is this side midpoint splitable // without violating aspect ratio? if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { // compute spread along this dim ANNcoord spr = annSpread(pa, pidx, n, d); if (spr > max_spread) { // best spread so far max_spread = spr; cut_dim = d; // this is dimension to cut } } } max_length = 0; // find longest side other than cut_dim for (d = 0; d < dim; d++) { ANNcoord length = bnds.hi[d] - bnds.lo[d]; if (d != cut_dim && length > max_length) max_length = length; } // consider most extreme splits ANNcoord small_piece = max_length / FS_ASPECT_RATIO; ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut // find min and max along cut_dim annMinMax(pa, pidx, n, cut_dim, min, max); // is median below lo_cut? if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { if (max > lo_cut) { // are any points above lo_cut? cut_val = lo_cut; // cut at lo_cut annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = br1; // balance if there are ties } else { // all points below lo_cut cut_val = max; // cut at max value annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = n-1; } } // is median above hi_cut? else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { if (min < hi_cut) { // are any points below hi_cut? cut_val = hi_cut; // cut at hi_cut annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = br2; // balance if there are ties } else { // all points above hi_cut cut_val = min; // cut at min value annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); n_lo = 1; } } else { // median cut is good enough n_lo = n/2; // split about median annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); } } mldemos-0.4.3/_3rdParty/ANN/kd_split.h000066400000000000000000000073261172143270300174330ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_split.h // Programmer: Sunil Arya and David Mount // Description: Methods for splitting kd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef ANN_KD_SPLIT_H #define ANN_KD_SPLIT_H #include "kd_tree.h" // kd-tree definitions //---------------------------------------------------------------------- // External entry points // These are all splitting procedures for kd-trees. //---------------------------------------------------------------------- void kd_split( // standard (optimized) kd-splitter ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) void midpt_split( // midpoint kd-splitter ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) void sl_midpt_split( // sliding midpoint kd-splitter ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) void fair_split( // fair-split kd-splitter ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) void sl_fair_split( // sliding fair-split kd-splitter ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) #endif mldemos-0.4.3/_3rdParty/ANN/kd_tree.cpp000066400000000000000000000365131172143270300175720ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_tree.cpp // Programmer: Sunil Arya and David Mount // Description: Basic methods for kd-trees. // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000. // Fixed leaf counts to count trivial leaves. // Added optional pa, pi arguments to Skeleton kd_tree constructor // for use in load constructor. // Added annClose() to eliminate KD_TRIVIAL memory leak. //---------------------------------------------------------------------- #include "kd_tree.h" // kd-tree declarations #include "kd_split.h" // kd-tree splitting rules #include "kd_util.h" // kd-tree utilities #include // performance evaluation //---------------------------------------------------------------------- // Global data // // For some splitting rules, especially with small bucket sizes, // it is possible to generate a large number of empty leaf nodes. // To save storage we allocate a single trivial leaf node which // contains no points. For messy coding reasons it is convenient // to have it reference a trivial point index. // // KD_TRIVIAL is allocated when the first kd-tree is created. It // must *never* deallocated (since it may be shared by more than // one tree). //---------------------------------------------------------------------- static int IDX_TRIVIAL[] = {0}; // trivial point index ANNkd_leaf *KD_TRIVIAL = NULL; // trivial leaf node //---------------------------------------------------------------------- // Printing the kd-tree // These routines print a kd-tree in reverse inorder (high then // root then low). (This is so that if you look at the output // from the right side it appear from left to right in standard // inorder.) When outputting leaves we output only the point // indices rather than the point coordinates. There is an option // to print the point coordinates separately. // // The tree printing routine calls the printing routines on the // individual nodes of the tree, passing in the level or depth // in the tree. The level in the tree is used to print indentation // for readability. //---------------------------------------------------------------------- void ANNkd_split::print( // print splitting node int level, // depth of node in tree ostream &out) // output stream { child[ANN_HI]->print(level+1, out); // print high child out << " "; for (int i = 0; i < level; i++) // print indentation out << ".."; out << "Split cd=" << cut_dim << " cv=" << cut_val; out << " lbnd=" << cd_bnds[ANN_LO]; out << " hbnd=" << cd_bnds[ANN_HI]; out << "\n"; child[ANN_LO]->print(level+1, out); // print low child } void ANNkd_leaf::print( // print leaf node int level, // depth of node in tree ostream &out) // output stream { out << " "; for (int i = 0; i < level; i++) // print indentation out << ".."; if (this == KD_TRIVIAL) { // canonical trivial leaf node out << "Leaf (trivial)\n"; } else{ out << "Leaf n=" << n_pts << " <"; for (int j = 0; j < n_pts; j++) { out << bkt[j]; if (j < n_pts-1) out << ","; } out << ">\n"; } } void ANNkd_tree::Print( // print entire tree ANNbool with_pts, // print points as well? ostream &out) // output stream { out << "ANN Version " << ANNversion << "\n"; if (with_pts) { // print point coordinates out << " Points:\n"; for (int i = 0; i < n_pts; i++) { out << "\t" << i << ": "; annPrintPt(pts[i], dim, out); out << "\n"; } } if (root == NULL) // empty tree? out << " Null tree.\n"; else { root->print(0, out); // invoke printing at root } } //---------------------------------------------------------------------- // kd_tree statistics (for performance evaluation) // This routine compute various statistics information for // a kd-tree. It is used by the implementors for performance // evaluation of the data structure. //---------------------------------------------------------------------- #define MAX(a,b) ((a) > (b) ? (a) : (b)) void ANNkdStats::merge(const ANNkdStats &st) // merge stats from child { n_lf += st.n_lf; n_tl += st.n_tl; n_spl += st.n_spl; n_shr += st.n_shr; depth = MAX(depth, st.depth); sum_ar += st.sum_ar; } //---------------------------------------------------------------------- // Update statistics for nodes //---------------------------------------------------------------------- const double ANN_AR_TOOBIG = 1000; // too big an aspect ratio void ANNkd_leaf::getStats( // get subtree statistics int dim, // dimension of space ANNkdStats &st, // stats (modified) ANNorthRect &bnd_box) // bounding box { st.reset(); st.n_lf = 1; // count this leaf if (this == KD_TRIVIAL) st.n_tl = 1; // count trivial leaf double ar = annAspectRatio(dim, bnd_box); // aspect ratio of leaf // incr sum (ignore outliers) st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG); } void ANNkd_split::getStats( // get subtree statistics int dim, // dimension of space ANNkdStats &st, // stats (modified) ANNorthRect &bnd_box) // bounding box { ANNkdStats ch_stats; // stats for children // get stats for low child ANNcoord hv = bnd_box.hi[cut_dim]; // save box bounds bnd_box.hi[cut_dim] = cut_val; // upper bound for low child ch_stats.reset(); // reset child[ANN_LO]->getStats(dim, ch_stats, bnd_box); st.merge(ch_stats); // merge them bnd_box.hi[cut_dim] = hv; // restore bound // get stats for high child ANNcoord lv = bnd_box.lo[cut_dim]; // save box bounds bnd_box.lo[cut_dim] = cut_val; // lower bound for high child ch_stats.reset(); // reset child[ANN_HI]->getStats(dim, ch_stats, bnd_box); st.merge(ch_stats); // merge them bnd_box.lo[cut_dim] = lv; // restore bound st.depth++; // increment depth st.n_spl++; // increment number of splits } //---------------------------------------------------------------------- // getStats // Collects a number of statistics related to kd_tree or // bd_tree. //---------------------------------------------------------------------- void ANNkd_tree::getStats( // get tree statistics ANNkdStats &st) // stats (modified) { st.reset(dim, n_pts, bkt_size); // reset stats // create bounding box ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi); if (root != NULL) { // if nonempty tree root->getStats(dim, st, bnd_box); // get statistics st.avg_ar = st.sum_ar / st.n_lf; // average leaf asp ratio } } //---------------------------------------------------------------------- // kd_tree destructor // The destructor just frees the various elements that were // allocated in the construction process. //---------------------------------------------------------------------- ANNkd_tree::~ANNkd_tree() // tree destructor { if (root != NULL) delete root; if (pidx != NULL) delete [] pidx; if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo); if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi); } //---------------------------------------------------------------------- // This is called with all use of ANN is finished. It eliminates the // minor memory leak caused by the allocation of KD_TRIVIAL. //---------------------------------------------------------------------- void annClose() // close use of ANN { if (KD_TRIVIAL != NULL) { delete KD_TRIVIAL; KD_TRIVIAL = NULL; } } //---------------------------------------------------------------------- // kd_tree constructors // There is a skeleton kd-tree constructor which sets up a // trivial empty tree. The last optional argument allows // the routine to be passed a point index array which is // assumed to be of the proper size (n). Otherwise, one is // allocated and initialized to the identity. Warning: In // either case the destructor will deallocate this array. // // As a kludge, we need to allocate KD_TRIVIAL if one has not // already been allocated. (This is because I'm too dumb to // figure out how to cause a pointer to be allocated at load // time.) //---------------------------------------------------------------------- void ANNkd_tree::SkeletonTree( // construct skeleton tree int n, // number of points int dd, // dimension int bs, // bucket size ANNpointArray pa, // point array ANNidxArray pi) // point indices { dim = dd; // initialize basic elements n_pts = n; bkt_size = bs; pts = pa; // initialize points array root = NULL; // no associated tree yet if (pi == NULL) { // point indices provided? pidx = new ANNidx[n]; // no, allocate space for point indices for (int i = 0; i < n; i++) { pidx[i] = i; // initially identity } } else { pidx = pi; // yes, use them } bnd_box_lo = bnd_box_hi = NULL; // bounding box is nonexistent if (KD_TRIVIAL == NULL) // no trivial leaf node yet? KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL); // allocate it } ANNkd_tree::ANNkd_tree( // basic constructor int n, // number of points int dd, // dimension int bs) // bucket size { SkeletonTree(n, dd, bs); } // construct skeleton tree //---------------------------------------------------------------------- // rkd_tree - recursive procedure to build a kd-tree // // Builds a kd-tree for points in pa as indexed through the // array pidx[0..n-1] (typically a subarray of the array used in // the top-level call). This routine permutes the array pidx, // but does not alter pa[]. // // The construction is based on a standard algorithm for constructing // the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for // finding best matches in logarithmic expected time,'' ACM Transactions // on Mathematical Software, 3(3):209-226, 1977). The procedure // operates by a simple divide-and-conquer strategy, which determines // an appropriate orthogonal cutting plane (see below), and splits // the points. When the number of points falls below the bucket size, // we simply store the points in a leaf node's bucket. // // One of the arguments is a pointer to a splitting routine, // whose prototype is: // // void split( // ANNpointArray pa, // complete point array // ANNidxArray pidx, // point array (permuted on return) // ANNorthRect &bnds, // bounds of current cell // int n, // number of points // int dim, // dimension of space // int &cut_dim, // cutting dimension // ANNcoord &cut_val, // cutting value // int &n_lo) // no. of points on low side of cut // // This procedure selects a cutting dimension and cutting value, // partitions pa about these values, and returns the number of // points on the low side of the cut. //---------------------------------------------------------------------- ANNkd_ptr rkd_tree( // recursive construction of kd-tree ANNpointArray pa, // point array ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space int bsp, // bucket space ANNorthRect &bnd_box, // bounding box for current node ANNkd_splitter splitter) // splitting routine { if (n <= bsp) { // n small, make a leaf node if (n == 0) // empty leaf node return KD_TRIVIAL; // return (canonical) empty leaf else // construct the node and return return new ANNkd_leaf(n, pidx); } else { // n large, make a splitting node int cd; // cutting dimension ANNcoord cv; // cutting value int n_lo; // number on low side of cut ANNkd_node *lo, *hi; // low and high children // invoke splitting procedure (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension ANNcoord hv = bnd_box.hi[cd]; bnd_box.hi[cd] = cv; // modify bounds for left subtree lo = rkd_tree( // build left subtree pa, pidx, n_lo, // ...from pidx[0..n_lo-1] dim, bsp, bnd_box, splitter); bnd_box.hi[cd] = hv; // restore bounds bnd_box.lo[cd] = cv; // modify bounds for right subtree hi = rkd_tree( // build right subtree pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] dim, bsp, bnd_box, splitter); bnd_box.lo[cd] = lv; // restore bounds // create the splitting node ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi); return ptr; // return pointer to this node } } //---------------------------------------------------------------------- // kd-tree constructor // This is the main constructor for kd-trees given a set of points. // It first builds a skeleton tree, then computes the bounding box // of the data points, and then invokes rkd_tree() to actually // build the tree, passing it the appropriate splitting routine. //---------------------------------------------------------------------- ANNkd_tree::ANNkd_tree( // construct from point array ANNpointArray pa, // point array (with at least n pts) int n, // number of points int dd, // dimension int bs, // bucket size ANNsplitRule split) // splitting method { SkeletonTree(n, dd, bs); // set up the basic stuff pts = pa; // where the points are if (n == 0) return; // no points--no sweat ANNorthRect bnd_box(dd); // bounding box for points annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle // copy to tree structure bnd_box_lo = annCopyPt(dd, bnd_box.lo); bnd_box_hi = annCopyPt(dd, bnd_box.hi); switch (split) { // build by rule case ANN_KD_STD: // standard kd-splitting rule root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split); break; case ANN_KD_MIDPT: // midpoint split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split); break; case ANN_KD_FAIR: // fair split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split); break; case ANN_KD_SUGGEST: // best (in our opinion) case ANN_KD_SL_MIDPT: // sliding midpoint split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split); break; case ANN_KD_SL_FAIR: // sliding fair split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split); break; default: annError("Illegal splitting method", ANNabort); } } mldemos-0.4.3/_3rdParty/ANN/kd_tree.h000066400000000000000000000177671172143270300172510ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_tree.h // Programmer: Sunil Arya and David Mount // Description: Declarations for standard kd-tree routines // Last modified: 05/03/05 (Version 1.1) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.1 05/03/05 // Added fixed radius kNN search //---------------------------------------------------------------------- #ifndef ANN_kd_tree_H #define ANN_kd_tree_H #include // all ANN includes using namespace std; // make std:: available //---------------------------------------------------------------------- // Generic kd-tree node // // Nodes in kd-trees are of two types, splitting nodes which contain // splitting information (a splitting hyperplane orthogonal to one // of the coordinate axes) and leaf nodes which contain point // information (an array of points stored in a bucket). This is // handled by making a generic class kd_node, which is essentially an // empty shell, and then deriving the leaf and splitting nodes from // this. //---------------------------------------------------------------------- class ANNkd_node{ // generic kd-tree node (empty shell) public: virtual ~ANNkd_node() {} // virtual distroyer virtual void ann_search(ANNdist) = 0; // tree search virtual void ann_pri_search(ANNdist) = 0; // priority search virtual void ann_FR_search(ANNdist) = 0; // fixed-radius search virtual void getStats( // get tree statistics int dim, // dimension of space ANNkdStats &st, // statistics ANNorthRect &bnd_box) = 0; // bounding box // print node virtual void print(int level, ostream &out) = 0; virtual void dump(ostream &out) = 0; // dump node friend class ANNkd_tree; // allow kd-tree to access us }; //---------------------------------------------------------------------- // kd-splitting function: // kd_splitter is a pointer to a splitting routine for preprocessing. // Different splitting procedures result in different strategies // for building the tree. //---------------------------------------------------------------------- typedef void (*ANNkd_splitter)( // splitting routine for kd-trees ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices (permuted on return) const ANNorthRect &bnds, // bounding rectangle for cell int n, // number of points int dim, // dimension of space int &cut_dim, // cutting dimension (returned) ANNcoord &cut_val, // cutting value (returned) int &n_lo); // num of points on low side (returned) //---------------------------------------------------------------------- // Leaf kd-tree node // Leaf nodes of the kd-tree store the set of points associated // with this bucket, stored as an array of point indices. These // are indices in the array points, which resides with the // root of the kd-tree. We also store the number of points // that reside in this bucket. //---------------------------------------------------------------------- class ANNkd_leaf: public ANNkd_node // leaf node for kd-tree { int n_pts; // no. points in bucket ANNidxArray bkt; // bucket of points public: ANNkd_leaf( // constructor int n, // number of points ANNidxArray b) // bucket { n_pts = n; // number of points in bucket bkt = b; // the bucket } ~ANNkd_leaf() { } // destructor (none) virtual void getStats( // get tree statistics int dim, // dimension of space ANNkdStats &st, // statistics ANNorthRect &bnd_box); // bounding box virtual void print(int level, ostream &out);// print node virtual void dump(ostream &out); // dump node virtual void ann_search(ANNdist); // standard search virtual void ann_pri_search(ANNdist); // priority search virtual void ann_FR_search(ANNdist); // fixed-radius search }; //---------------------------------------------------------------------- // KD_TRIVIAL is a special pointer to an empty leaf node. Since // some splitting rules generate many (more than 50%) trivial // leaves, we use this one shared node to save space. // // The pointer is initialized to NULL, but whenever a kd-tree is // created, we allocate this node, if it has not already been // allocated. This node is *never* deallocated, so it produces // a small memory leak. //---------------------------------------------------------------------- extern ANNkd_leaf *KD_TRIVIAL; // trivial (empty) leaf node //---------------------------------------------------------------------- // kd-tree splitting node. // Splitting nodes contain a cutting dimension and a cutting value. // These indicate the axis-parellel plane which subdivide the // box for this node. The extent of the bounding box along the // cutting dimension is maintained (this is used to speed up point // to box distance calculations) [we do not store the entire bounding // box since this may be wasteful of space in high dimensions]. // We also store pointers to the 2 children. //---------------------------------------------------------------------- class ANNkd_split : public ANNkd_node // splitting node of a kd-tree { int cut_dim; // dim orthogonal to cutting plane ANNcoord cut_val; // location of cutting plane ANNcoord cd_bnds[2]; // lower and upper bounds of // rectangle along cut_dim ANNkd_ptr child[2]; // left and right children public: ANNkd_split( // constructor int cd, // cutting dimension ANNcoord cv, // cutting value ANNcoord lv, ANNcoord hv, // low and high values ANNkd_ptr lc=NULL, ANNkd_ptr hc=NULL) // children { cut_dim = cd; // cutting dimension cut_val = cv; // cutting value cd_bnds[ANN_LO] = lv; // lower bound for rectangle cd_bnds[ANN_HI] = hv; // upper bound for rectangle child[ANN_LO] = lc; // left child child[ANN_HI] = hc; // right child } ~ANNkd_split() // destructor { if (child[ANN_LO]!= NULL && child[ANN_LO]!= KD_TRIVIAL) delete child[ANN_LO]; if (child[ANN_HI]!= NULL && child[ANN_HI]!= KD_TRIVIAL) delete child[ANN_HI]; } virtual void getStats( // get tree statistics int dim, // dimension of space ANNkdStats &st, // statistics ANNorthRect &bnd_box); // bounding box virtual void print(int level, ostream &out);// print node virtual void dump(ostream &out); // dump node virtual void ann_search(ANNdist); // standard search virtual void ann_pri_search(ANNdist); // priority search virtual void ann_FR_search(ANNdist); // fixed-radius search }; //---------------------------------------------------------------------- // External entry points //---------------------------------------------------------------------- ANNkd_ptr rkd_tree( // recursive construction of kd-tree ANNpointArray pa, // point array (unaltered) ANNidxArray pidx, // point indices to store in subtree int n, // number of points int dim, // dimension of space int bsp, // bucket space ANNorthRect &bnd_box, // bounding box for current node ANNkd_splitter splitter); // splitting routine #endif mldemos-0.4.3/_3rdParty/ANN/kd_util.cpp000066400000000000000000000366211172143270300176100ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_util.cpp // Programmer: Sunil Arya and David Mount // Description: Common utilities for kd-trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #include "kd_util.h" // kd-utility declarations #include // performance evaluation //---------------------------------------------------------------------- // The following routines are utility functions for manipulating // points sets, used in determining splitting planes for kd-tree // construction. //---------------------------------------------------------------------- //---------------------------------------------------------------------- // NOTE: Virtually all point indexing is done through an index (i.e. // permutation) array pidx. Consequently, a reference to the d-th // coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d) // is a shorthand for this. //---------------------------------------------------------------------- // standard 2-d indirect indexing #define PA(i,d) (pa[pidx[(i)]][(d)]) // accessing a single point #define PP(i) (pa[pidx[(i)]]) //---------------------------------------------------------------------- // annAspectRatio // Compute the aspect ratio (ratio of longest to shortest side) // of a rectangle. //---------------------------------------------------------------------- double annAspectRatio( int dim, // dimension const ANNorthRect &bnd_box) // bounding cube { ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0]; ANNcoord min_length = length; // min side length ANNcoord max_length = length; // max side length for (int d = 0; d < dim; d++) { length = bnd_box.hi[d] - bnd_box.lo[d]; if (length < min_length) min_length = length; if (length > max_length) max_length = length; } return max_length/min_length; } //---------------------------------------------------------------------- // annEnclRect, annEnclCube // These utilities compute the smallest rectangle and cube enclosing // a set of points, respectively. //---------------------------------------------------------------------- void annEnclRect( ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension ANNorthRect &bnds) // bounding cube (returned) { for (int d = 0; d < dim; d++) { // find smallest enclosing rectangle ANNcoord lo_bnd = PA(0,d); // lower bound on dimension d ANNcoord hi_bnd = PA(0,d); // upper bound on dimension d for (int i = 0; i < n; i++) { if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d); else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d); } bnds.lo[d] = lo_bnd; bnds.hi[d] = hi_bnd; } } void annEnclCube( // compute smallest enclosing cube ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension ANNorthRect &bnds) // bounding cube (returned) { int d; // compute smallest enclosing rect annEnclRect(pa, pidx, n, dim, bnds); ANNcoord max_len = 0; // max length of any side for (d = 0; d < dim; d++) { // determine max side length ANNcoord len = bnds.hi[d] - bnds.lo[d]; if (len > max_len) { // update max_len if longest max_len = len; } } for (d = 0; d < dim; d++) { // grow sides to match max ANNcoord len = bnds.hi[d] - bnds.lo[d]; ANNcoord half_diff = (max_len - len) / 2; bnds.lo[d] -= half_diff; bnds.hi[d] += half_diff; } } //---------------------------------------------------------------------- // annBoxDistance - utility routine which computes distance from point to // box (Note: most distances to boxes are computed using incremental // distance updates, not this function.) //---------------------------------------------------------------------- ANNdist annBoxDistance( // compute distance from point to box const ANNpoint q, // the point const ANNpoint lo, // low point of box const ANNpoint hi, // high point of box int dim) // dimension of space { register ANNdist dist = 0.0; // sum of squared distances register ANNdist t; for (register int d = 0; d < dim; d++) { if (q[d] < lo[d]) { // q is left of box t = ANNdist(lo[d]) - ANNdist(q[d]); } else if (q[d] > hi[d]) { // q is right of box t = ANNdist(q[d]) - ANNdist(hi[d]); } switch(ANN::MetricType) { case ANN_METRIC0: dist = ANN_SUM0(dist, ANN_POW0(t)); break; case ANN_METRIC1: dist = ANN_SUM1(dist, ANN_POW1(t)); break; case ANN_METRIC2: dist = ANN_SUM(dist, ANN_POW(t)); break; case ANN_METRICP: dist = ANN_SUMp(dist, ANN_POWp(t)); break; } } ANN_FLOP(4*dim) // increment floating op count return dist; } //---------------------------------------------------------------------- // annSpread - find spread along given dimension // annMinMax - find min and max coordinates along given dimension // annMaxSpread - find dimension of max spread //---------------------------------------------------------------------- ANNcoord annSpread( // compute point spread along dimension ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int d) // dimension to check { ANNcoord min = PA(0,d); // compute max and min coords ANNcoord max = PA(0,d); for (int i = 1; i < n; i++) { ANNcoord c = PA(i,d); if (c < min) min = c; else if (c > max) max = c; } return (max - min); // total spread is difference } void annMinMax( // compute min and max coordinates along dim ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int d, // dimension to check ANNcoord &min, // minimum value (returned) ANNcoord &max) // maximum value (returned) { min = PA(0,d); // compute max and min coords max = PA(0,d); for (int i = 1; i < n; i++) { ANNcoord c = PA(i,d); if (c < min) min = c; else if (c > max) max = c; } } int annMaxSpread( // compute dimension of max spread ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim) // dimension of space { int max_dim = 0; // dimension of max spread ANNcoord max_spr = 0; // amount of max spread if (n == 0) return max_dim; // no points, who cares? for (int d = 0; d < dim; d++) { // compute spread along each dim ANNcoord spr = annSpread(pa, pidx, n, d); if (spr > max_spr) { // bigger than current max max_spr = spr; max_dim = d; } } return max_dim; } //---------------------------------------------------------------------- // annMedianSplit - split point array about its median // Splits a subarray of points pa[0..n] about an element of given // rank (median: n_lo = n/2) with respect to dimension d. It places // the element of rank n_lo-1 correctly (because our splitting rule // takes the mean of these two). On exit, the array is permuted so // that: // // pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d]. // // The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the // splitting value. // // All indexing is done indirectly through the index array pidx. // // This function uses the well known selection algorithm due to // C.A.R. Hoare. //---------------------------------------------------------------------- // swap two points in pa array #define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; } void annMedianSplit( ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord &cv, // cutting value int n_lo) // split into n_lo and n-n_lo { int l = 0; // left end of current subarray int r = n-1; // right end of current subarray while (l < r) { register int i = (r+l)/2; // select middle as pivot register int k; if (PA(i,d) > PA(r,d)) // make sure last > pivot PASWAP(i,r) PASWAP(l,i); // move pivot to first position ANNcoord c = PA(l,d); // pivot value i = l; k = r; for(;;) { // pivot about c while (PA(++i,d) < c) ; while (PA(--k,d) > c) ; if (i < k) PASWAP(i,k) else break; } PASWAP(l,k); // pivot winds up in location k if (k > n_lo) r = k-1; // recurse on proper subarray else if (k < n_lo) l = k+1; else break; // got the median exactly } if (n_lo > 0) { // search for next smaller item ANNcoord c = PA(0,d); // candidate for max int k = 0; // candidate's index for (int i = 1; i < n_lo; i++) { if (PA(i,d) > c) { c = PA(i,d); k = i; } } PASWAP(n_lo-1, k); // max among pa[0..n_lo-1] to pa[n_lo-1] } // cut value is midpoint value cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0; } //---------------------------------------------------------------------- // annPlaneSplit - split point array about a cutting plane // Split the points in an array about a given plane along a // given cutting dimension. On exit, br1 and br2 are set so // that: // // pa[ 0 ..br1-1] < cv // pa[br1..br2-1] == cv // pa[br2.. n -1] > cv // // All indexing is done indirectly through the index array pidx. // //---------------------------------------------------------------------- void annPlaneSplit( // split points by a plane ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord cv, // cutting value int &br1, // first break (values < cv) int &br2) // second break (values == cv) { int l = 0; int r = n-1; for(;;) { // partition pa[0..n-1] about cv while (l < n && PA(l,d) < cv) l++; while (r >= 0 && PA(r,d) >= cv) r--; if (l > r) break; PASWAP(l,r); l++; r--; } br1 = l; // now: pa[0..br1-1] < cv <= pa[br1..n-1] r = n-1; for(;;) { // partition pa[br1..n-1] about cv while (l < n && PA(l,d) <= cv) l++; while (r >= br1 && PA(r,d) > cv) r--; if (l > r) break; PASWAP(l,r); l++; r--; } br2 = l; // now: pa[br1..br2-1] == cv < pa[br2..n-1] } //---------------------------------------------------------------------- // annBoxSplit - split point array about a orthogonal rectangle // Split the points in an array about a given orthogonal // rectangle. On exit, n_in is set to the number of points // that are inside (or on the boundary of) the rectangle. // // All indexing is done indirectly through the index array pidx. // //---------------------------------------------------------------------- void annBoxSplit( // split points by a box ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension of space ANNorthRect &box, // the box int &n_in) // number of points inside (returned) { int l = 0; int r = n-1; for(;;) { // partition pa[0..n-1] about box while (l < n && box.inside(dim, PP(l))) l++; while (r >= 0 && !box.inside(dim, PP(r))) r--; if (l > r) break; PASWAP(l,r); l++; r--; } n_in = l; // now: pa[0..n_in-1] inside and rest outside } //---------------------------------------------------------------------- // annSplitBalance - compute balance factor for a given plane split // Balance factor is defined as the number of points lying // below the splitting value minus n/2 (median). Thus, a // median split has balance 0, left of this is negative and // right of this is positive. (The points are unchanged.) //---------------------------------------------------------------------- int annSplitBalance( // determine balance factor of a split ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord cv) // cutting value { int n_lo = 0; for(int i = 0; i < n; i++) { // count number less than cv if (PA(i,d) < cv) n_lo++; } return n_lo - n/2; } //---------------------------------------------------------------------- // annBox2Bnds - convert bounding box to list of bounds // Given two boxes, an inner box enclosed within a bounding // box, this routine determines all the sides for which the // inner box is strictly contained with the bounding box, // and adds an appropriate entry to a list of bounds. Then // we allocate storage for the final list of bounds, and return // the resulting list and its size. //---------------------------------------------------------------------- void annBox2Bnds( // convert inner box to bounds const ANNorthRect &inner_box, // inner box const ANNorthRect &bnd_box, // enclosing box int dim, // dimension of space int &n_bnds, // number of bounds (returned) ANNorthHSArray &bnds) // bounds array (returned) { int i; n_bnds = 0; // count number of bounds for (i = 0; i < dim; i++) { if (inner_box.lo[i] > bnd_box.lo[i]) // low bound is inside n_bnds++; if (inner_box.hi[i] < bnd_box.hi[i]) // high bound is inside n_bnds++; } bnds = new ANNorthHalfSpace[n_bnds]; // allocate appropriate size int j = 0; for (i = 0; i < dim; i++) { // fill the array if (inner_box.lo[i] > bnd_box.lo[i]) { bnds[j].cd = i; bnds[j].cv = inner_box.lo[i]; bnds[j].sd = +1; j++; } if (inner_box.hi[i] < bnd_box.hi[i]) { bnds[j].cd = i; bnds[j].cv = inner_box.hi[i]; bnds[j].sd = -1; j++; } } } //---------------------------------------------------------------------- // annBnds2Box - convert list of bounds to bounding box // Given an enclosing box and a list of bounds, this routine // computes the corresponding inner box. It is assumed that // the box points have been allocated already. //---------------------------------------------------------------------- void annBnds2Box( const ANNorthRect &bnd_box, // enclosing box int dim, // dimension of space int n_bnds, // number of bounds ANNorthHSArray bnds, // bounds array ANNorthRect &inner_box) // inner box (returned) { annAssignRect(dim, inner_box, bnd_box); // copy bounding box to inner for (int i = 0; i < n_bnds; i++) { bnds[i].project(inner_box.lo); // project each endpoint bnds[i].project(inner_box.hi); } } mldemos-0.4.3/_3rdParty/ANN/kd_util.h000066400000000000000000000114131172143270300172450ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: kd_util.h // Programmer: Sunil Arya and David Mount // Description: Common utilities for kd- trees // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef ANN_kd_util_H #define ANN_kd_util_H #include "kd_tree.h" // kd-tree declarations //---------------------------------------------------------------------- // externally accessible functions //---------------------------------------------------------------------- double annAspectRatio( // compute aspect ratio of box int dim, // dimension const ANNorthRect &bnd_box); // bounding cube void annEnclRect( // compute smallest enclosing rectangle ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension ANNorthRect &bnds); // bounding cube (returned) void annEnclCube( // compute smallest enclosing cube ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension ANNorthRect &bnds); // bounding cube (returned) ANNdist annBoxDistance( // compute distance from point to box const ANNpoint q, // the point const ANNpoint lo, // low point of box const ANNpoint hi, // high point of box int dim); // dimension of space ANNcoord annSpread( // compute point spread along dimension ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int d); // dimension to check void annMinMax( // compute min and max coordinates along dim ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int d, // dimension to check ANNcoord& min, // minimum value (returned) ANNcoord& max); // maximum value (returned) int annMaxSpread( // compute dimension of max spread ANNpointArray pa, // point array ANNidxArray pidx, // point indices int n, // number of points int dim); // dimension of space void annMedianSplit( // split points along median value ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord &cv, // cutting value int n_lo); // split into n_lo and n-n_lo void annPlaneSplit( // split points by a plane ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord cv, // cutting value int &br1, // first break (values < cv) int &br2); // second break (values == cv) void annBoxSplit( // split points by a box ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int dim, // dimension of space ANNorthRect &box, // the box int &n_in); // number of points inside (returned) int annSplitBalance( // determine balance factor of a split ANNpointArray pa, // points to split ANNidxArray pidx, // point indices int n, // number of points int d, // dimension along which to split ANNcoord cv); // cutting value void annBox2Bnds( // convert inner box to bounds const ANNorthRect &inner_box, // inner box const ANNorthRect &bnd_box, // enclosing box int dim, // dimension of space int &n_bnds, // number of bounds (returned) ANNorthHSArray &bnds); // bounds array (returned) void annBnds2Box( // convert bounds to inner box const ANNorthRect &bnd_box, // enclosing box int dim, // dimension of space int n_bnds, // number of bounds ANNorthHSArray bnds, // bounds array ANNorthRect &inner_box); // inner box (returned) #endif mldemos-0.4.3/_3rdParty/ANN/perf.cpp000066400000000000000000000125731172143270300171110ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: perf.cpp // Programmer: Sunil Arya and David Mount // Description: Methods for performance stats // Last modified: 01/27/10 (Version 1.1.2) //---------------------------------------------------------------------- // Copyright (c) 1997-2010 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release // Revision 1.0 04/01/05 // Changed names to avoid namespace conflicts. // Added flush after printing performance stats to fix bug // in Microsoft Windows version. // Revision 1.1.2 01/27/10 // Fixed minor compilation bugs for new versions of gcc //---------------------------------------------------------------------- #include // basic ANN includes #include // performance includes using namespace std; // make std:: available //---------------------------------------------------------------------- // Performance statistics // The following data and routines are used for computing // performance statistics for nearest neighbor searching. // Because these routines can slow the code down, they can be // activated and deactiviated by defining the PERF variable, // by compiling with the option: -DPERF //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Global counters for performance measurement //---------------------------------------------------------------------- int ann_Ndata_pts = 0; // number of data points int ann_Nvisit_lfs = 0; // number of leaf nodes visited int ann_Nvisit_spl = 0; // number of splitting nodes visited int ann_Nvisit_shr = 0; // number of shrinking nodes visited int ann_Nvisit_pts = 0; // visited points for one query int ann_Ncoord_hts = 0; // coordinate hits for one query int ann_Nfloat_ops = 0; // floating ops for one query ANNsampStat ann_visit_lfs; // stats on leaf nodes visits ANNsampStat ann_visit_spl; // stats on splitting nodes visits ANNsampStat ann_visit_shr; // stats on shrinking nodes visits ANNsampStat ann_visit_nds; // stats on total nodes visits ANNsampStat ann_visit_pts; // stats on points visited ANNsampStat ann_coord_hts; // stats on coordinate hits ANNsampStat ann_float_ops; // stats on floating ops // ANNsampStat ann_average_err; // average error ANNsampStat ann_rank_err; // rank error //---------------------------------------------------------------------- // Routines for statistics. //---------------------------------------------------------------------- DLL_API void annResetStats(int data_size) // reset stats for a set of queries { ann_Ndata_pts = data_size; ann_visit_lfs.reset(); ann_visit_spl.reset(); ann_visit_shr.reset(); ann_visit_nds.reset(); ann_visit_pts.reset(); ann_coord_hts.reset(); ann_float_ops.reset(); ann_average_err.reset(); ann_rank_err.reset(); } DLL_API void annResetCounts() // reset counts for one query { ann_Nvisit_lfs = 0; ann_Nvisit_spl = 0; ann_Nvisit_shr = 0; ann_Nvisit_pts = 0; ann_Ncoord_hts = 0; ann_Nfloat_ops = 0; } DLL_API void annUpdateStats() // update stats with current counts { ann_visit_lfs += ann_Nvisit_lfs; ann_visit_nds += ann_Nvisit_spl + ann_Nvisit_lfs; ann_visit_spl += ann_Nvisit_spl; ann_visit_shr += ann_Nvisit_shr; ann_visit_pts += ann_Nvisit_pts; ann_coord_hts += ann_Ncoord_hts; ann_float_ops += ann_Nfloat_ops; } // print a single statistic void print_one_stat(const char* title, ANNsampStat s, double div) { cout << title << "= [ "; cout.width(9); cout << s.mean()/div << " : "; cout.width(9); cout << s.stdDev()/div << " ]<"; cout.width(9); cout << s.min()/div << " , "; cout.width(9); cout << s.max()/div << " >\n"; } DLL_API void annPrintStats( // print statistics for a run ANNbool validate) // true if average errors desired { cout.precision(4); // set floating precision cout << " (Performance stats: " << " [ mean : stddev ]< min , max >\n"; print_one_stat(" leaf_nodes ", ann_visit_lfs, 1); print_one_stat(" splitting_nodes ", ann_visit_spl, 1); print_one_stat(" shrinking_nodes ", ann_visit_shr, 1); print_one_stat(" total_nodes ", ann_visit_nds, 1); print_one_stat(" points_visited ", ann_visit_pts, 1); print_one_stat(" coord_hits/pt ", ann_coord_hts, ann_Ndata_pts); print_one_stat(" floating_ops_(K) ", ann_float_ops, 1000); if (validate) { print_one_stat(" average_error ", ann_average_err, 1); print_one_stat(" rank_error ", ann_rank_err, 1); } cout.precision(0); // restore the default cout << " )\n"; cout.flush(); } mldemos-0.4.3/_3rdParty/ANN/pr_queue.h000066400000000000000000000110141172143270300174340ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: pr_queue.h // Programmer: Sunil Arya and David Mount // Description: Include file for priority queue and related // structures. // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef PR_QUEUE_H #define PR_QUEUE_H #include // all ANN includes #include // performance evaluation //---------------------------------------------------------------------- // Basic types. //---------------------------------------------------------------------- typedef void *PQinfo; // info field is generic pointer typedef ANNdist PQkey; // key field is distance //---------------------------------------------------------------------- // Priority queue // A priority queue is a list of items, along with associated // priorities. The basic operations are insert and extract_minimum. // // The priority queue is maintained using a standard binary heap. // (Implementation note: Indexing is performed from [1..max] rather // than the C standard of [0..max-1]. This simplifies parent/child // computations.) User information consists of a void pointer, // and the user is responsible for casting this quantity into whatever // useful form is desired. // // Because the priority queue is so central to the efficiency of // query processing, all the code is inline. //---------------------------------------------------------------------- class ANNpr_queue { struct pq_node { // node in priority queue PQkey key; // key value PQinfo info; // info field }; int n; // number of items in queue int max_size; // maximum queue size pq_node *pq; // the priority queue (array of nodes) public: ANNpr_queue(int max) // constructor (given max size) { n = 0; // initially empty max_size = max; // maximum number of items pq = new pq_node[max+1]; // queue is array [1..max] of nodes } ~ANNpr_queue() // destructor { delete [] pq; } ANNbool empty() // is queue empty? { if (n==0) return ANNtrue; else return ANNfalse; } ANNbool non_empty() // is queue nonempty? { if (n==0) return ANNfalse; else return ANNtrue; } void reset() // make existing queue empty { n = 0; } inline void insert( // insert item (inlined for speed) PQkey kv, // key value PQinfo inf) // item info { if (++n > max_size) annError("Priority queue overflow.", ANNabort); register int r = n; while (r > 1) { // sift up new item register int p = r/2; ANN_FLOP(1) // increment floating ops if (pq[p].key <= kv) // in proper order break; pq[r] = pq[p]; // else swap with parent r = p; } pq[r].key = kv; // insert new item at final location pq[r].info = inf; } inline void extr_min( // extract minimum (inlined for speed) PQkey &kv, // key (returned) PQinfo &inf) // item info (returned) { kv = pq[1].key; // key of min item inf = pq[1].info; // information of min item register PQkey kn = pq[n--].key;// last item in queue register int p = 1; // p points to item out of position register int r = p<<1; // left child of p while (r <= n) { // while r is still within the heap ANN_FLOP(2) // increment floating ops // set r to smaller child of p if (r < n && pq[r].key > pq[r+1].key) r++; if (kn <= pq[r].key) // in proper order break; pq[p] = pq[r]; // else swap with child p = r; // advance pointers r = p<<1; } pq[p] = pq[n+1]; // insert last item in proper place } }; #endif mldemos-0.4.3/_3rdParty/ANN/pr_queue_k.h000066400000000000000000000106361172143270300177570ustar00rootroot00000000000000//---------------------------------------------------------------------- // File: pr_queue_k.h // Programmer: Sunil Arya and David Mount // Description: Include file for priority queue with k items. // Last modified: 01/04/05 (Version 1.0) //---------------------------------------------------------------------- // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and // David Mount. All Rights Reserved. // // This software and related documentation is part of the Approximate // Nearest Neighbor Library (ANN). This software is provided under // the provisions of the Lesser GNU Public License (LGPL). See the // file ../ReadMe.txt for further information. // // The University of Maryland (U.M.) and the authors make no // representations about the suitability or fitness of this software for // any purpose. It is provided "as is" without express or implied // warranty. //---------------------------------------------------------------------- // History: // Revision 0.1 03/04/98 // Initial release //---------------------------------------------------------------------- #ifndef PR_QUEUE_K_H #define PR_QUEUE_K_H #include // all ANN includes #include // performance evaluation //---------------------------------------------------------------------- // Basic types //---------------------------------------------------------------------- typedef ANNdist PQKkey; // key field is distance typedef int PQKinfo; // info field is int //---------------------------------------------------------------------- // Constants // The NULL key value is used to initialize the priority queue, and // so it should be larger than any valid distance, so that it will // be replaced as legal distance values are inserted. The NULL // info value must be a nonvalid array index, we use ANN_NULL_IDX, // which is guaranteed to be negative. //---------------------------------------------------------------------- const PQKkey PQ_NULL_KEY = ANN_DIST_INF; // nonexistent key value const PQKinfo PQ_NULL_INFO = ANN_NULL_IDX; // nonexistent info value //---------------------------------------------------------------------- // ANNmin_k // An ANNmin_k structure is one which maintains the smallest // k values (of type PQKkey) and associated information (of type // PQKinfo). The special info and key values PQ_NULL_INFO and // PQ_NULL_KEY means that thise entry is empty. // // It is currently implemented using an array with k items. // Items are stored in increasing sorted order, and insertions // are made through standard insertion sort. (This is quite // inefficient, but current applications call for small values // of k and relatively few insertions.) // // Note that the list contains k+1 entries, but the last entry // is used as a simple placeholder and is otherwise ignored. //---------------------------------------------------------------------- class ANNmin_k { struct mk_node { // node in min_k structure PQKkey key; // key value PQKinfo info; // info field (user defined) }; int k; // max number of keys to store int n; // number of keys currently active mk_node *mk; // the list itself public: ANNmin_k(int max) // constructor (given max size) { n = 0; // initially no items k = max; // maximum number of items mk = new mk_node[max+1]; // sorted array of keys } ~ANNmin_k() // destructor { delete [] mk; } PQKkey ANNmin_key() // return minimum key { return (n > 0 ? mk[0].key : PQ_NULL_KEY); } PQKkey max_key() // return maximum key { return (n == k ? mk[k-1].key : PQ_NULL_KEY); } PQKkey ith_smallest_key(int i) // ith smallest key (i in [0..n-1]) { return (i < n ? mk[i].key : PQ_NULL_KEY); } PQKinfo ith_smallest_info(int i) // info for ith smallest (i in [0..n-1]) { return (i < n ? mk[i].info : PQ_NULL_INFO); } inline void insert( // insert item (inlined for speed) PQKkey kv, // key value PQKinfo inf) // item info { register int i; // slide larger values up for (i = n; i > 0; i--) { if (mk[i-1].key > kv) mk[i] = mk[i-1]; else break; } mk[i].key = kv; // store element here mk[i].info = inf; if (n < k) n++; // increment number of items ANN_FLOP(k-i+1) // increment floating ops } }; #endif mldemos-0.4.3/_3rdParty/Eigen/000077500000000000000000000000001172143270300160545ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/Eigen/Array000066400000000000000000000004601172143270300170550ustar00rootroot00000000000000#ifndef EIGEN_ARRAY_MODULE_H #define EIGEN_ARRAY_MODULE_H // include Core first to handle Eigen2 support macros #include "Core" #ifndef EIGEN2_SUPPORT #error The Eigen/Array header does no longer exist in Eigen3. All that functionality has moved to Eigen/Core. #endif #endif // EIGEN_ARRAY_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/CMakeLists.txt000066400000000000000000000011371172143270300206160ustar00rootroot00000000000000include(RegexUtils) test_escape_string_as_regex() file(GLOB Eigen_directory_files "*") escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") foreach(f ${Eigen_directory_files}) if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/src") list(APPEND Eigen_directory_files_to_install ${f}) endif() endforeach(f ${Eigen_directory_files}) install(FILES ${Eigen_directory_files_to_install} DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel ) add_subdirectory(src) mldemos-0.4.3/_3rdParty/Eigen/Cholesky000066400000000000000000000013561172143270300175650ustar00rootroot00000000000000#ifndef EIGEN_CHOLESKY_MODULE_H #define EIGEN_CHOLESKY_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup Cholesky_Module Cholesky module * * * * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. * Those decompositions are accessible via the following MatrixBase methods: * - MatrixBase::llt(), * - MatrixBase::ldlt() * * \code * #include * \endcode */ #include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLESKY_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/Core000066400000000000000000000302011172143270300166630ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2011 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_CORE_H #define EIGEN_CORE_H // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" // then include this file where all our macros are defined. It's really important to do it first because // it's where we do all the alignment settings (platform detection and honoring the user's will if he // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. #include "src/Core/util/Macros.h" // if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into // account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks #if !EIGEN_ALIGN #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #endif #ifdef _MSC_VER #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled #if (_MSC_VER >= 1500) // 2008 or later // Remember that usage of defined() in a #define is undefined by the standard. // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER #endif #endif #endif // Remember that usage of defined() in a #define is undefined by the standard #if (defined __SSE2__) && ( (!defined __GNUC__) || EIGEN_GNUC_AT_LEAST(4,2) ) #define EIGEN_SSE2_BUT_NOT_OLD_GCC #endif #ifndef EIGEN_DONT_VECTORIZE #if defined (EIGEN_SSE2_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER) // Defines symbols for compile-time detection of which instructions are // used. // EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_SSE #define EIGEN_VECTORIZE_SSE2 // Detect sse3/ssse3/sse4: // gcc and icc defines __SSE3__, ... // there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you // want to force the use of those instructions with msvc. #ifdef __SSE3__ #define EIGEN_VECTORIZE_SSE3 #endif #ifdef __SSSE3__ #define EIGEN_VECTORIZE_SSSE3 #endif #ifdef __SSE4_1__ #define EIGEN_VECTORIZE_SSE4_1 #endif #ifdef __SSE4_2__ #define EIGEN_VECTORIZE_SSE4_2 #endif // include files // This extern "C" works around a MINGW-w64 compilation issue // https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354 // In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do). // However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations // with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know; // so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too. // notice that since these are C headers, the extern "C" is theoretically needed anyways. extern "C" { #include #include #ifdef EIGEN_VECTORIZE_SSE3 #include #endif #ifdef EIGEN_VECTORIZE_SSSE3 #include #endif #ifdef EIGEN_VECTORIZE_SSE4_1 #include #endif #ifdef EIGEN_VECTORIZE_SSE4_2 #include #endif } // end extern "C" #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ALTIVEC #include // We need to #undef all these ugly tokens defined in // => use __vector instead of vector #undef bool #undef vector #undef pixel #elif defined __ARM_NEON__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include #endif #endif #if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) #define EIGEN_HAS_OPENMP #endif #ifdef EIGEN_HAS_OPENMP #include #endif // MSVC for windows mobile does not have the errno.h file #if !(defined(_MSC_VER) && defined(_WIN32_WCE)) #define EIGEN_HAS_ERRNO #endif #ifdef EIGEN_HAS_ERRNO #include #endif #include #include #include #include #include #include #include #include #include #include // for CHAR_BIT // for min/max: #include // for outputting debug info #ifdef EIGEN_DEBUG_ASSIGN #include #endif // required for __cpuid, needs to be included after cmath #if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) #include #endif #if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(EIGEN_NO_EXCEPTIONS) #define EIGEN_EXCEPTIONS #endif #ifdef EIGEN_EXCEPTIONS #include #endif // this needs to be done after all possible windows C header includes and before any Eigen source includes // (system C++ includes are supposed to be able to deal with this already): // windows.h defines min and max macros which would make Eigen fail to compile. #if defined(min) || defined(max) #error The preprocessor symbols 'min' or 'max' are defined. If you are compiling on Windows, do #define NOMINMAX to prevent windows.h from defining these symbols. #endif // defined in bits/termios.h #undef B0 namespace Eigen { inline static const char *SimdInstructionSetsInUse(void) { #if defined(EIGEN_VECTORIZE_SSE4_2) return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_1) return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; #elif defined(EIGEN_VECTORIZE_SSSE3) return "SSE, SSE2, SSE3, SSSE3"; #elif defined(EIGEN_VECTORIZE_SSE3) return "SSE, SSE2, SSE3"; #elif defined(EIGEN_VECTORIZE_SSE2) return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; #else return "None"; #endif } #define STAGE10_FULL_EIGEN2_API 10 #define STAGE20_RESOLVE_API_CONFLICTS 20 #define STAGE30_FULL_EIGEN3_API 30 #define STAGE40_FULL_EIGEN3_STRICTNESS 40 #define STAGE99_NO_EIGEN2_SUPPORT 99 #if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS #define EIGEN2_SUPPORT #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS #elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API #define EIGEN2_SUPPORT #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API #elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS #define EIGEN2_SUPPORT #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS #elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API #define EIGEN2_SUPPORT #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API #elif defined EIGEN2_SUPPORT // default to stage 3, that's what it's always meant #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API #else #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT #endif #ifdef EIGEN2_SUPPORT #undef minor #endif // we use size_t frequently and we'll never remember to prepend it with std:: everytime just to // ensure QNX/QCC support using std::size_t; /** \defgroup Core_Module Core module * This is the main module of Eigen providing dense matrix and vector support * (both fixed and dynamic size) with all the features corresponding to a BLAS library * and much more... * * \code * #include * \endcode */ #include "src/Core/util/Constants.h" #include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/Memory.h" #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" #include "src/Core/GenericPacketMath.h" #if defined EIGEN_VECTORIZE_SSE #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" #elif defined EIGEN_VECTORIZE_ALTIVEC #include "src/Core/arch/AltiVec/PacketMath.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" #include "src/Core/arch/NEON/Complex.h" #endif #include "src/Core/arch/Default/Settings.h" #include "src/Core/Functors.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 #include "src/Core/Assign.h" #endif #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" #include "src/Core/ForceAlignedAccess.h" #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" #include "src/Core/Matrix.h" #include "src/Core/Array.h" #include "src/Core/CwiseBinaryOp.h" #include "src/Core/CwiseUnaryOp.h" #include "src/Core/CwiseNullaryOp.h" #include "src/Core/CwiseUnaryView.h" #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" #include "src/Core/MapBase.h" #include "src/Core/Stride.h" #include "src/Core/Map.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" #include "src/Core/PermutationMatrix.h" #include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" #include "src/Core/IO.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" #include "src/Core/Flagged.h" #include "src/Core/ProductBase.h" #include "src/Core/Product.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/SolveTriangular.h" #include "src/Core/products/Parallelizer.h" #include "src/Core/products/CoeffBasedProduct.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/products/GeneralMatrixMatrixTriangular.h" #include "src/Core/products/SelfadjointMatrixVector.h" #include "src/Core/products/SelfadjointMatrixMatrix.h" #include "src/Core/products/SelfadjointProduct.h" #include "src/Core/products/SelfadjointRank2Update.h" #include "src/Core/products/TriangularMatrixVector.h" #include "src/Core/products/TriangularMatrixMatrix.h" #include "src/Core/products/TriangularSolverMatrix.h" #include "src/Core/products/TriangularSolverVector.h" #include "src/Core/BandMatrix.h" #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" #include "src/Core/VectorwiseOp.h" #include "src/Core/Random.h" #include "src/Core/Replicate.h" #include "src/Core/Reverse.h" #include "src/Core/ArrayBase.h" #include "src/Core/ArrayWrapper.h" } // namespace Eigen #include "src/Core/GlobalFunctions.h" #include "src/Core/util/ReenableStupidWarnings.h" #ifdef EIGEN2_SUPPORT #include "Eigen2Support" #endif #endif // EIGEN_CORE_H mldemos-0.4.3/_3rdParty/Eigen/Dense000066400000000000000000000001721172143270300170350ustar00rootroot00000000000000#include "Core" #include "LU" #include "Cholesky" #include "QR" #include "SVD" #include "Geometry" #include "Eigenvalues" mldemos-0.4.3/_3rdParty/Eigen/Eigen000066400000000000000000000000451172143270300170250ustar00rootroot00000000000000#include "Dense" //#include "Sparse" mldemos-0.4.3/_3rdParty/Eigen/Eigen2Support000066400000000000000000000051661172143270300205150ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN2SUPPORT_H #define EIGEN2SUPPORT_H #if (!defined(EIGEN2_SUPPORT)) || (!defined(EIGEN_CORE_H)) #error Eigen2 support must be enabled by defining EIGEN2_SUPPORT before including any Eigen header #endif #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup Eigen2Support_Module Eigen2 support module * This module provides a couple of deprecated functions improving the compatibility with Eigen2. * * To use it, define EIGEN2_SUPPORT before including any Eigen header * \code * #define EIGEN2_SUPPORT * \endcode * */ #include "src/Eigen2Support/Macros.h" #include "src/Eigen2Support/Memory.h" #include "src/Eigen2Support/Meta.h" #include "src/Eigen2Support/Lazy.h" #include "src/Eigen2Support/Cwise.h" #include "src/Eigen2Support/CwiseOperators.h" #include "src/Eigen2Support/TriangularSolver.h" #include "src/Eigen2Support/Block.h" #include "src/Eigen2Support/VectorBlock.h" #include "src/Eigen2Support/Minor.h" #include "src/Eigen2Support/MathFunctions.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" // Eigen2 used to include iostream #include #define USING_PART_OF_NAMESPACE_EIGEN \ EIGEN_USING_MATRIX_TYPEDEFS \ using Eigen::Matrix; \ using Eigen::MatrixBase; \ using Eigen::ei_random; \ using Eigen::ei_real; \ using Eigen::ei_imag; \ using Eigen::ei_conj; \ using Eigen::ei_abs; \ using Eigen::ei_abs2; \ using Eigen::ei_sqrt; \ using Eigen::ei_exp; \ using Eigen::ei_log; \ using Eigen::ei_sin; \ using Eigen::ei_cos; #endif // EIGEN2SUPPORT_H mldemos-0.4.3/_3rdParty/Eigen/Eigenvalues000066400000000000000000000021761172143270300202540ustar00rootroot00000000000000#ifndef EIGEN_EIGENVALUES_MODULE_H #define EIGEN_EIGENVALUES_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include "Cholesky" #include "Jacobi" #include "Householder" #include "LU" namespace Eigen { /** \defgroup Eigenvalues_Module Eigenvalues module * * * * This module mainly provides various eigenvalue solvers. * This module also provides some MatrixBase methods, including: * - MatrixBase::eigenvalues(), * - MatrixBase::operatorNorm() * * \code * #include * \endcode */ #include "src/Eigenvalues/Tridiagonalization.h" #include "src/Eigenvalues/RealSchur.h" #include "src/Eigenvalues/EigenSolver.h" #include "src/Eigenvalues/SelfAdjointEigenSolver.h" #include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h" #include "src/Eigenvalues/HessenbergDecomposition.h" #include "src/Eigenvalues/ComplexSchur.h" #include "src/Eigenvalues/ComplexEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_EIGENVALUES_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/Geometry000066400000000000000000000031561172143270300175770ustar00rootroot00000000000000#ifndef EIGEN_GEOMETRY_MODULE_H #define EIGEN_GEOMETRY_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include "SVD" #include "LU" #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace Eigen { /** \defgroup Geometry_Module Geometry module * * * * This module provides support for: * - fixed-size homogeneous transformations * - translation, scaling, 2D and 3D rotations * - quaternions * - \ref MatrixBase::cross() "cross product" * - \ref MatrixBase::unitOrthogonal() "orthognal vector generation" * - some linear components: parametrized-lines and hyperplanes * * \code * #include * \endcode */ #include "src/Geometry/OrthoMethods.h" #include "src/Geometry/EulerAngles.h" #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS #include "src/Geometry/Homogeneous.h" #include "src/Geometry/RotationBase.h" #include "src/Geometry/Rotation2D.h" #include "src/Geometry/Quaternion.h" #include "src/Geometry/AngleAxis.h" #include "src/Geometry/Transform.h" #include "src/Geometry/Translation.h" #include "src/Geometry/Scaling.h" #include "src/Geometry/Hyperplane.h" #include "src/Geometry/ParametrizedLine.h" #include "src/Geometry/AlignedBox.h" #include "src/Geometry/Umeyama.h" #if defined EIGEN_VECTORIZE_SSE #include "src/Geometry/arch/Geometry_SSE.h" #endif #endif #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/Geometry/All.h" #endif } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_GEOMETRY_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/Householder000066400000000000000000000011551172143270300202620ustar00rootroot00000000000000#ifndef EIGEN_HOUSEHOLDER_MODULE_H #define EIGEN_HOUSEHOLDER_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup Householder_Module Householder module * This module provides Householder transformations. * * \code * #include * \endcode */ #include "src/Householder/Householder.h" #include "src/Householder/HouseholderSequence.h" #include "src/Householder/BlockHouseholder.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_HOUSEHOLDER_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/Jacobi000066400000000000000000000012561172143270300171720ustar00rootroot00000000000000#ifndef EIGEN_JACOBI_MODULE_H #define EIGEN_JACOBI_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup Jacobi_Module Jacobi module * This module provides Jacobi and Givens rotations. * * \code * #include * \endcode * * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation: * - MatrixBase::applyOnTheLeft() * - MatrixBase::applyOnTheRight(). */ #include "src/Jacobi/Jacobi.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_JACOBI_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/LU000066400000000000000000000016731172143270300163260ustar00rootroot00000000000000#ifndef EIGEN_LU_MODULE_H #define EIGEN_LU_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup LU_Module LU module * This module includes %LU decomposition and related notions such as matrix inversion and determinant. * This module defines the following MatrixBase methods: * - MatrixBase::inverse() * - MatrixBase::determinant() * * \code * #include * \endcode */ #include "src/misc/Solve.h" #include "src/misc/Kernel.h" #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" #include "src/LU/PartialPivLU.h" #include "src/LU/Determinant.h" #include "src/LU/Inverse.h" #if defined EIGEN_VECTORIZE_SSE #include "src/LU/arch/Inverse_SSE.h" #endif #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/LU.h" #endif } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/LeastSquares000066400000000000000000000013611172143270300204140ustar00rootroot00000000000000#ifndef EIGEN_REGRESSION_MODULE_H #define EIGEN_REGRESSION_MODULE_H #ifndef EIGEN2_SUPPORT #error LeastSquares is only available in Eigen2 support mode (define EIGEN2_SUPPORT) #endif // exclude from normal eigen3-only documentation #ifdef EIGEN2_SUPPORT #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include "Eigenvalues" #include "Geometry" namespace Eigen { /** \defgroup LeastSquares_Module LeastSquares module * This module provides linear regression and related features. * * \code * #include * \endcode */ #include "src/Eigen2Support/LeastSquares.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN2_SUPPORT #endif // EIGEN_REGRESSION_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/QR000066400000000000000000000015251172143270300163240ustar00rootroot00000000000000#ifndef EIGEN_QR_MODULE_H #define EIGEN_QR_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include "Cholesky" #include "Jacobi" #include "Householder" namespace Eigen { /** \defgroup QR_Module QR module * * * * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: * - MatrixBase::qr(), * * \code * #include * \endcode */ #include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/QR.h" #endif } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #ifdef EIGEN2_SUPPORT #include "Eigenvalues" #endif #endif // EIGEN_QR_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/QtAlignedMalloc000066400000000000000000000011751172143270300210030ustar00rootroot00000000000000 #ifndef EIGEN_QTMALLOC_MODULE_H #define EIGEN_QTMALLOC_MODULE_H #include "Core" #if (!EIGEN_MALLOC_ALREADY_ALIGNED) #include "src/Core/util/DisableStupidWarnings.h" void *qMalloc(size_t size) { return Eigen::internal::aligned_malloc(size); } void qFree(void *ptr) { Eigen::internal::aligned_free(ptr); } void *qRealloc(void *ptr, size_t size) { void* newPtr = Eigen::internal::aligned_malloc(size); memcpy(newPtr, ptr, size); Eigen::internal::aligned_free(ptr); return newPtr; } #include "src/Core/util/ReenableStupidWarnings.h" #endif #endif // EIGEN_QTMALLOC_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/SVD000066400000000000000000000014071172143270300164350ustar00rootroot00000000000000#ifndef EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H #include "QR" #include "Householder" #include "Jacobi" #include "src/Core/util/DisableStupidWarnings.h" namespace Eigen { /** \defgroup SVD_Module SVD module * * * * This module provides SVD decomposition for (currently) real matrices. * This decomposition is accessible via the following MatrixBase method: * - MatrixBase::svd() * * \code * #include * \endcode */ #include "src/misc/Solve.h" #include "src/SVD/JacobiSVD.h" #include "src/SVD/UpperBidiagonalization.h" #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/SVD.h" #endif } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SVD_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ mldemos-0.4.3/_3rdParty/Eigen/Sparse000066400000000000000000000035431172143270300172410ustar00rootroot00000000000000#ifndef EIGEN_SPARSE_MODULE_H #define EIGEN_SPARSE_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include #include #include #include #include #ifdef EIGEN2_SUPPORT #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET #endif #ifndef EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET #error The sparse module API is not stable yet. To use it anyway, please define the EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET preprocessor token. #endif namespace Eigen { /** \defgroup Sparse_Module Sparse module * * * * See the \ref TutorialSparse "Sparse tutorial" * * \code * #include * \endcode */ /** The type used to identify a general sparse storage. */ struct Sparse {}; #include "src/Sparse/SparseUtil.h" #include "src/Sparse/SparseMatrixBase.h" #include "src/Sparse/CompressedStorage.h" #include "src/Sparse/AmbiVector.h" #include "src/Sparse/SparseMatrix.h" #include "src/Sparse/DynamicSparseMatrix.h" #include "src/Sparse/MappedSparseMatrix.h" #include "src/Sparse/SparseVector.h" #include "src/Sparse/CoreIterators.h" #include "src/Sparse/SparseBlock.h" #include "src/Sparse/SparseTranspose.h" #include "src/Sparse/SparseCwiseUnaryOp.h" #include "src/Sparse/SparseCwiseBinaryOp.h" #include "src/Sparse/SparseDot.h" #include "src/Sparse/SparseAssign.h" #include "src/Sparse/SparseRedux.h" #include "src/Sparse/SparseFuzzy.h" #include "src/Sparse/SparseProduct.h" #include "src/Sparse/SparseSparseProduct.h" #include "src/Sparse/SparseDenseProduct.h" #include "src/Sparse/SparseDiagonalProduct.h" #include "src/Sparse/SparseTriangularView.h" #include "src/Sparse/SparseSelfAdjointView.h" #include "src/Sparse/TriangularSolver.h" #include "src/Sparse/SparseView.h" } // namespace Eigen #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SPARSE_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/StdDeque000066400000000000000000000027511172143270300175220ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_STDDEQUE_MODULE_H #define EIGEN_STDDEQUE_MODULE_H #include "Core" #include #if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) #else #include "src/StlSupport/StdDeque.h" #endif #endif // EIGEN_STDDEQUE_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/StdList000066400000000000000000000026461172143270300173750ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_STDLIST_MODULE_H #define EIGEN_STDLIST_MODULE_H #include "Core" #include #if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) #else #include "src/StlSupport/StdList.h" #endif #endif // EIGEN_STDLIST_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/StdVector000066400000000000000000000027571172143270300177270ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_STDVECTOR_MODULE_H #define EIGEN_STDVECTOR_MODULE_H #include "Core" #include #if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) #else #include "src/StlSupport/StdVector.h" #endif #endif // EIGEN_STDVECTOR_MODULE_H mldemos-0.4.3/_3rdParty/Eigen/src/000077500000000000000000000000001172143270300166435ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/Eigen/src/CMakeLists.txt000066400000000000000000000004641172143270300214070ustar00rootroot00000000000000file(GLOB Eigen_src_subdirectories "*") escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") foreach(f ${Eigen_src_subdirectories}) if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" ) add_subdirectory(${f}) endif() endforeach() mldemos-0.4.3/_3rdParty/Eigen/src/Cholesky/000077500000000000000000000000001172143270300204245ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/Eigen/src/Cholesky/CMakeLists.txt000066400000000000000000000002311172143270300231600ustar00rootroot00000000000000FILE(GLOB Eigen_Cholesky_SRCS "*.h") INSTALL(FILES ${Eigen_Cholesky_SRCS} DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Cholesky COMPONENT Devel ) mldemos-0.4.3/_3rdParty/Eigen/src/Cholesky/LDLT.h000066400000000000000000000363651172143270300213510ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2009 Keir Mierle // Copyright (C) 2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H namespace internal { template struct LDLT_Traits; } /** \ingroup cholesky_Module * * \class LDLT * * \brief Robust Cholesky decomposition of a matrix with pivoting * * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition * * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L * is lower triangular with a unit diagonal and D is a diagonal matrix. * * The decomposition uses pivoting to ensure stability, so that L will have * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root * on D also stabilizes the computation. * * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * * \sa MatrixBase::ldlt(), class LLT */ /* THIS PART OF THE DOX IS CURRENTLY DISABLED BECAUSE INACCURATE BECAUSE OF BUG IN THE DECOMPOSITION CODE * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ template class LDLT { public: typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options & ~RowMajorBit, // these are the options for the TmpMatrixType, we need a ColMajor matrix here! MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; typedef PermutationMatrix PermutationType; typedef internal::LDLT_Traits Traits; /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ LDLT() : m_matrix(), m_transpositions(), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. * \sa LDLT() */ LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), m_isInitialized(false) {} LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_isInitialized(false) { compute(matrix); } /** \returns a view of the upper triangular matrix U */ inline typename Traits::MatrixU matrixU() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return Traits::getU(m_matrix); } /** \returns a view of the lower triangular matrix L */ inline typename Traits::MatrixL matrixL() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return Traits::getL(m_matrix); } /** \returns the permutation matrix P as a transposition sequence. */ inline const TranspositionType& transpositionsP() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_transpositions; } /** \returns the coefficients of the diagonal matrix D */ inline Diagonal vectorD(void) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_matrix.diagonal(); } /** \returns true if the matrix is positive (semidefinite) */ inline bool isPositive(void) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == 1; } #ifdef EIGEN2_SUPPORT inline bool isPositiveDefinite() const { return isPositive(); } #endif /** \returns true if the matrix is negative (semidefinite) */ inline bool isNegative(void) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == -1; } /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. * * \note_about_checking_solutions * * \sa solveInPlace(), MatrixBase::ldlt() */ template inline const internal::solve_retval solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } #ifdef EIGEN2_SUPPORT template bool solve(const MatrixBase& b, ResultType *result) const { *result = this->solve(b); return true; } #endif template bool solveInPlace(MatrixBase &bAndX) const; LDLT& compute(const MatrixType& matrix); /** \returns the internal LDLT decomposition matrix * * TODO: document the storage layout */ inline const MatrixType& matrixLDLT() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_matrix; } MatrixType reconstructedMatrix() const; inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } protected: /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. * The strict upper part is used during the decomposition, the strict lower * part correspond to the coefficients of L (its diagonal is equal to 1 and * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; TranspositionType m_transpositions; TmpMatrixType m_temporary; int m_sign; bool m_isInitialized; }; namespace internal { template struct ldlt_inplace; template<> struct ldlt_inplace { template static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) { typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef typename MatrixType::Index Index; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); if (size <= 1) { transpositions.setIdentity(); if(sign) *sign = real(mat.coeff(0,0))>0 ? 1:-1; return true; } RealScalar cutoff = 0, biggest_in_corner; for (Index k = 0; k < size; ++k) { // Find largest diagonal element Index index_of_biggest_in_corner; biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; if(k == 0) { // The biggest overall is the point of reference to which further diagonals // are compared; if any diagonal is negligible compared // to the largest overall, the algorithm bails. cutoff = abs(NumTraits::epsilon() * biggest_in_corner); if(sign) *sign = real(mat.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; } // Finish early if the matrix is not full rank. if(biggest_in_corner < cutoff) { for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i; break; } transpositions.coeffRef(k) = index_of_biggest_in_corner; if(k != index_of_biggest_in_corner) { // apply the transposition while taking care to consider only // the lower triangular part Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); for(int i=k+1;i::IsComplex) mat.coeffRef(index_of_biggest_in_corner,k) = conj(mat.coeff(index_of_biggest_in_corner,k)); } // partition the matrix: // A00 | - | - // lu = A10 | A11 | - // A20 | A21 | A22 Index rs = size - k - 1; Block A21(mat,k+1,k,rs,1); Block A10(mat,k,0,1,k); Block A20(mat,k+1,0,rs,k); if(k>0) { temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint(); mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); if(rs>0) A21.noalias() -= A20 * temp.head(k); } if((rs>0) && (abs(mat.coeffRef(k,k)) > cutoff)) A21 /= mat.coeffRef(k,k); } return true; } }; template<> struct ldlt_inplace { template static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) { Transpose matt(mat); return ldlt_inplace::unblocked(matt, transpositions, temp, sign); } }; template struct LDLT_Traits { typedef TriangularView MatrixL; typedef TriangularView MatrixU; inline static MatrixL getL(const MatrixType& m) { return m; } inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; template struct LDLT_Traits { typedef TriangularView MatrixL; typedef TriangularView MatrixU; inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } inline static MatrixU getU(const MatrixType& m) { return m; } }; } // end namespace internal /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ template LDLT& LDLT::compute(const MatrixType& a) { eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix = a; m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign); m_isInitialized = true; return *this; } namespace internal { template struct solve_retval, Rhs> : solve_retval_base, Rhs> { typedef LDLT<_MatrixType,_UpLo> LDLTType; EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) template void evalTo(Dest& dst) const { eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); // dst = P b dst = dec().transpositionsP() * rhs(); // dst = L^-1 (P b) dec().matrixL().solveInPlace(dst); // dst = D^-1 (L^-1 P b) dst = dec().vectorD().asDiagonal().inverse() * dst; // dst = L^-T (D^-1 L^-1 P b) dec().matrixU().solveInPlace(dst); // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b dst = dec().transpositionsP().transpose() * dst; } }; } /** \internal use x = ldlt_object.solve(x); * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. * * This version avoids a copy when the right hand side matrix b is not * needed anymore. * * \sa LDLT::solve(), MatrixBase::ldlt() */ template template bool LDLT::solveInPlace(MatrixBase &bAndX) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); eigen_assert(size == bAndX.rows()); bAndX = this->solve(bAndX); return true; } /** \returns the matrix represented by the decomposition, * i.e., it returns the product: P^T L D L^* P. * This function is provided for debug purpose. */ template MatrixType LDLT::reconstructedMatrix() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); MatrixType res(size,size); // P res.setIdentity(); res = transpositionsP() * res; // L^* P res = matrixU() * res; // D(L^*P) res = vectorD().asDiagonal() * res; // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) res = transpositionsP().transpose() * res; return res; } /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this */ template inline const LDLT::PlainObject, UpLo> SelfAdjointView::ldlt() const { return LDLT(m_matrix); } /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this */ template inline const LDLT::PlainObject> MatrixBase::ldlt() const { return LDLT(derived()); } #endif // EIGEN_LDLT_H mldemos-0.4.3/_3rdParty/Eigen/src/Cholesky/LLT.h000066400000000000000000000307711172143270300212400ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_LLT_H #define EIGEN_LLT_H namespace internal{ template struct LLT_Traits; } /** \ingroup cholesky_Module * * \class LLT * * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features * * \param MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition * * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite * matrix A such that A = LL^* = U^*U, where L is lower triangular. * * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b, * for that purpose, we recommend the Cholesky decomposition without square root which is more stable * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other * situations like generalised eigen problems with hermitian matrices. * * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices, * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations * has a solution. * * \sa MatrixBase::llt(), class LDLT */ /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH) * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ template class LLT { public: typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; enum { PacketSize = internal::packet_traits::size, AlignmentMask = int(PacketSize)-1, UpLo = _UpLo }; typedef internal::LLT_Traits Traits; /** * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via LLT::compute(const MatrixType&). */ LLT() : m_matrix(), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. * \sa LLT() */ LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} LLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { compute(matrix); } /** \returns a view of the upper triangular matrix U */ inline typename Traits::MatrixU matrixU() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return Traits::getU(m_matrix); } /** \returns a view of the lower triangular matrix L */ inline typename Traits::MatrixL matrixL() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return Traits::getL(m_matrix); } /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * Since this LLT class assumes anyway that the matrix A is invertible, the solution * theoretically exists and is unique regardless of b. * * Example: \include LLT_solve.cpp * Output: \verbinclude LLT_solve.out * * \sa solveInPlace(), MatrixBase::llt() */ template inline const internal::solve_retval solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } #ifdef EIGEN2_SUPPORT template bool solve(const MatrixBase& b, ResultType *result) const { *result = this->solve(b); return true; } bool isPositiveDefinite() const { return true; } #endif template void solveInPlace(MatrixBase &bAndX) const; LLT& compute(const MatrixType& matrix); /** \returns the LLT decomposition matrix * * TODO: document the storage layout */ inline const MatrixType& matrixLLT() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return m_matrix; } MatrixType reconstructedMatrix() const; /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, * \c NumericalIssue if the matrix.appears to be negative. */ ComputationInfo info() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return m_info; } inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } protected: /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. */ MatrixType m_matrix; bool m_isInitialized; ComputationInfo m_info; }; namespace internal { template struct llt_inplace; template<> struct llt_inplace { template static typename MatrixType::Index unblocked(MatrixType& mat) { typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); for(Index k = 0; k < size; ++k) { Index rs = size-k-1; // remaining size Block A21(mat,k+1,k,rs,1); Block A10(mat,k,0,1,k); Block A20(mat,k+1,0,rs,k); RealScalar x = real(mat.coeff(k,k)); if (k>0) x -= A10.squaredNorm(); if (x<=RealScalar(0)) return k; mat.coeffRef(k,k) = x = sqrt(x); if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); if (rs>0) A21 *= RealScalar(1)/x; } return -1; } template static typename MatrixType::Index blocked(MatrixType& m) { typedef typename MatrixType::Index Index; eigen_assert(m.rows()==m.cols()); Index size = m.rows(); if(size<32) return unblocked(m); Index blockSize = size/8; blockSize = (blockSize/16)*16; blockSize = std::min(std::max(blockSize,Index(8)), Index(128)); for (Index k=0; k A11(m,k, k, bs,bs); Block A21(m,k+bs,k, rs,bs); Block A22(m,k+bs,k+bs,rs,rs); Index ret; if((ret=unblocked(A11))>=0) return k+ret; if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); if(rs>0) A22.template selfadjointView().rankUpdate(A21,-1); // bottleneck } return -1; } }; template<> struct llt_inplace { template static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::unblocked(matt); } template static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::blocked(matt); } }; template struct LLT_Traits { typedef TriangularView MatrixL; typedef TriangularView MatrixU; inline static MatrixL getL(const MatrixType& m) { return m; } inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; template struct LLT_Traits { typedef TriangularView MatrixL; typedef TriangularView MatrixU; inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } inline static MatrixU getU(const MatrixType& m) { return m; } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; } // end namespace internal /** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix * * * \returns a reference to *this */ template LLT& LLT::compute(const MatrixType& a) { assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); m_matrix = a; m_isInitialized = true; bool ok = Traits::inplace_decomposition(m_matrix); m_info = ok ? Success : NumericalIssue; return *this; } namespace internal { template struct solve_retval, Rhs> : solve_retval_base, Rhs> { typedef LLT<_MatrixType,UpLo> LLTType; EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) template void evalTo(Dest& dst) const { dst = rhs(); dec().solveInPlace(dst); } }; } /** \internal use x = llt_object.solve(x); * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. * * This version avoids a copy when the right hand side matrix b is not * needed anymore. * * \sa LLT::solve(), MatrixBase::llt() */ template template void LLT::solveInPlace(MatrixBase &bAndX) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==bAndX.rows()); matrixL().solveInPlace(bAndX); matrixU().solveInPlace(bAndX); } /** \returns the matrix represented by the decomposition, * i.e., it returns the product: L L^*. * This function is provided for debug purpose. */ template MatrixType LLT::reconstructedMatrix() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return matrixL() * matrixL().adjoint().toDenseMatrix(); } /** \cholesky_module * \returns the LLT decomposition of \c *this */ template inline const LLT::PlainObject> MatrixBase::llt() const { return LLT(derived()); } /** \cholesky_module * \returns the LLT decomposition of \c *this */ template inline const LLT::PlainObject, UpLo> SelfAdjointView::llt() const { return LLT(m_matrix); } #endif // EIGEN_LLT_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/000077500000000000000000000000001172143270300175335ustar00rootroot00000000000000mldemos-0.4.3/_3rdParty/Eigen/src/Core/Array.h000066400000000000000000000304151172143270300207650ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_ARRAY_H #define EIGEN_ARRAY_H /** \class Array * \ingroup Core_Module * * \brief General-purpose arrays with easy API for coefficient-wise operations * * The %Array class is very similar to the Matrix class. It provides * general-purpose one- and two-dimensional arrays. The difference between the * %Array and the %Matrix class is primarily in the API: the API for the * %Array class provides easy access to coefficient-wise operations, while the * API for the %Matrix class provides easy access to linear-algebra * operations. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. * * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy */ namespace internal { template struct traits > : traits > { typedef ArrayXpr XprKind; typedef ArrayBase > XprBase; }; } template class Array : public PlainObjectBase > { public: typedef PlainObjectBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Array) enum { Options = _Options }; typedef typename Base::PlainObject PlainObject; protected: template friend struct internal::conservative_resize_like_impl; using Base::m_storage; public: enum { NeedsToAlign = (!(Options&DontAlign)) && SizeAtCompileTime!=Dynamic && ((static_cast(sizeof(Scalar))*SizeAtCompileTime)%16)==0 }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) using Base::base; using Base::coeff; using Base::coeffRef; /** * The usage of * using Base::operator=; * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped * the usage of 'using'. This should be done only for operator=. */ template EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) { return Base::operator=(other); } /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) { return Base::_set(other); } /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); } /** Default constructor. * * For fixed-size matrices, does nothing. * * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix * is called a null matrix. This constructor is the unique way to create null matrices: resizing * a matrix to 0 is not supported. * * \sa resize(Index,Index) */ EIGEN_STRONG_INLINE explicit Array() : Base() { Base::_check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ?? /** \internal */ Array(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #endif /** Constructs a vector or row-vector with given dimension. \only_for_vectors * * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, * it is redundant to pass the dimension here, so it makes more sense to use the default * constructor Matrix() instead. */ EIGEN_STRONG_INLINE explicit Array(Index dim) : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) eigen_assert(dim >= 0); eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_STRONG_INLINE Array(const T0& x, const T1& y) { Base::_check_template_params(); this->template _init2(x, y); } #else /** constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor * Matrix() instead. */ Array(Index rows, Index cols); /** constructs an initialized 2D vector with given coefficients */ Array(const Scalar& x, const Scalar& y); #endif /** constructs an initialized 3D vector with given coefficients */ EIGEN_STRONG_INLINE Array(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; } /** constructs an initialized 4D vector with given coefficients */ EIGEN_STRONG_INLINE Array(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; m_storage.data()[3] = w; } explicit Array(const Scalar *data); /** Constructor copying the value of the expression \a other */ template EIGEN_STRONG_INLINE Array(const ArrayBase& other) : Base(other.rows() * other.cols(), other.rows(), other.cols()) { Base::_check_template_params(); Base::_set_noalias(other); } /** Copy constructor */ EIGEN_STRONG_INLINE Array(const Array& other) : Base(other.rows() * other.cols(), other.rows(), other.cols()) { Base::_check_template_params(); Base::_set_noalias(other); } /** Copy constructor with in-place evaluation */ template EIGEN_STRONG_INLINE Array(const ReturnByValue& other) { Base::_check_template_params(); Base::resize(other.rows(), other.cols()); other.evalTo(*this); } /** \sa MatrixBase::operator=(const EigenBase&) */ template EIGEN_STRONG_INLINE Array(const EigenBase &other) : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) { Base::_check_template_params(); Base::resize(other.rows(), other.cols()); *this = other; } /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the * data pointers. */ template void swap(ArrayBase const & other) { this->_swap(other.derived()); } inline Index innerStride() const { return 1; } inline Index outerStride() const { return this->innerSize(); } #ifdef EIGEN_ARRAY_PLUGIN #include EIGEN_ARRAY_PLUGIN #endif private: template friend struct internal::matrix_swap_impl; }; /** \defgroup arraytypedefs Global array typedefs * \ingroup Core_Module * * Eigen defines several typedef shortcuts for most common 1D and 2D array types. * * The general patterns are the following: * * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd * for complex double. * * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats. * * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is * a fixed-size 1D array of 4 complex floats. * * \sa class Array */ #define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ /** \ingroup arraytypedefs */ \ typedef Array Array##SizeSuffix##SizeSuffix##TypeSuffix; \ /** \ingroup arraytypedefs */ \ typedef Array Array##SizeSuffix##TypeSuffix; #define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ /** \ingroup arraytypedefs */ \ typedef Array Array##Size##X##TypeSuffix; \ /** \ingroup arraytypedefs */ \ typedef Array Array##X##Size##TypeSuffix; #define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cf) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cd) #undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES #undef EIGEN_MAKE_ARRAY_TYPEDEFS #undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE #define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ using Eigen::Matrix##SizeSuffix##TypeSuffix; \ using Eigen::Vector##SizeSuffix##TypeSuffix; \ using Eigen::RowVector##SizeSuffix##TypeSuffix; #define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ #define EIGEN_USING_ARRAY_TYPEDEFS \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) #endif // EIGEN_ARRAY_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/ArrayBase.h000066400000000000000000000216751172143270300215700ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_ARRAYBASE_H #define EIGEN_ARRAYBASE_H template class MatrixWrapper; /** \class ArrayBase * \ingroup Core_Module * * \brief Base class for all 1D and 2D array, and related expressions * * An array is similar to a dense vector or matrix. While matrices are mathematical * objects with well defined linear algebra operators, an array is just a collection * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence, * all operations applied to an array are performed coefficient wise. Furthermore, * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient * constructors allowing to easily write generic code working for both scalar values * and arrays. * * This class is the base that is inherited by all array expression types. * * \tparam Derived is the derived type, e.g., an array or an expression type. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. * * \sa class MatrixBase, \ref TopicClassHierarchy */ template class ArrayBase : public DenseBase { public: #ifndef EIGEN_PARSED_BY_DOXYGEN /** The base class for a given storage type. */ typedef ArrayBase StorageBaseType; typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; using internal::special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real>::operator*; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::CoeffReadCost; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::operator=; using Base::operator+=; using Base::operator-=; using Base::operator*=; using Base::operator/=; typedef typename Base::CoeffReturnType CoeffReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either * PlainObject or const PlainObject&. */ typedef Array::Scalar, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime, AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), internal::traits::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime > PlainObject; /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Derived> ConstantReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/ArrayCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseBinaryOps.h" # include "../plugins/ArrayCwiseBinaryOps.h" # ifdef EIGEN_ARRAYBASE_PLUGIN # include EIGEN_ARRAYBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ Derived& operator=(const ArrayBase& other) { return internal::assign_selector::run(derived(), other.derived()); } Derived& operator+=(const Scalar& scalar) { return *this = derived() + scalar; } Derived& operator-=(const Scalar& scalar) { return *this = derived() - scalar; } template Derived& operator+=(const ArrayBase& other); template Derived& operator-=(const ArrayBase& other); template Derived& operator*=(const ArrayBase& other); template Derived& operator/=(const ArrayBase& other); public: ArrayBase& array() { return *this; } const ArrayBase& array() const { return *this; } /** \returns an \link MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ MatrixWrapper matrix() { return derived(); } const MatrixWrapper matrix() const { return derived(); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } protected: ArrayBase() : Base() {} private: explicit ArrayBase(Index); ArrayBase(Index,Index); template explicit ArrayBase(const ArrayBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const MatrixBase& ) {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} // mixing arrays and matrices is not legal template Derived& operator-=(const MatrixBase& ) {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} }; /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & ArrayBase::operator-=(const ArrayBase &other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } /** replaces \c *this by \c *this + \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & ArrayBase::operator+=(const ArrayBase& other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } /** replaces \c *this by \c *this * \a other coefficient wise. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } /** replaces \c *this by \c *this / \a other coefficient wise. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & ArrayBase::operator/=(const ArrayBase& other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } #endif // EIGEN_ARRAYBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/ArrayWrapper.h000066400000000000000000000152351172143270300223310ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_ARRAYWRAPPER_H #define EIGEN_ARRAYWRAPPER_H /** \class ArrayWrapper * \ingroup Core_Module * * \brief Expression of a mathematical vector or matrix as an array object * * This class is the return type of MatrixBase::array(), and most of the time * this is the only way it is use. * * \sa MatrixBase::array(), class MatrixWrapper */ namespace internal { template struct traits > : public traits::type > { typedef ArrayXpr XprKind; }; } template class ArrayWrapper : public ArrayBase > { public: typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) typedef typename internal::nested::type NestedExpressionType; inline ArrayWrapper(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } inline Index outerStride() const { return m_expression.outerStride(); } inline Index innerStride() const { return m_expression.innerStride(); } inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } inline const Scalar& coeffRef(Index row, Index col) const { return m_expression.const_cast_derived().coeffRef(row, col); } inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } inline const Scalar& coeffRef(Index index) const { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } template inline void evalTo(Dest& dst) const { dst = m_expression; } protected: const NestedExpressionType m_expression; }; /** \class MatrixWrapper * \ingroup Core_Module * * \brief Expression of an array as a mathematical vector or matrix * * This class is the return type of ArrayBase::matrix(), and most of the time * this is the only way it is use. * * \sa MatrixBase::matrix(), class ArrayWrapper */ namespace internal { template struct traits > : public traits::type > { typedef MatrixXpr XprKind; }; } template class MatrixWrapper : public MatrixBase > { public: typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) typedef typename internal::nested::type NestedExpressionType; inline MatrixWrapper(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } inline Index outerStride() const { return m_expression.outerStride(); } inline Index innerStride() const { return m_expression.innerStride(); } inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } inline const Scalar& coeffRef(Index row, Index col) const { return m_expression.derived().coeffRef(row, col); } inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } inline const Scalar& coeffRef(Index index) const { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } protected: const NestedExpressionType m_expression; }; #endif // EIGEN_ARRAYWRAPPER_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Assign.h000066400000000000000000000553321172143270300211400ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007 Michael Olbrich // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_ASSIGN_H #define EIGEN_ASSIGN_H namespace internal { /*************************************************************************** * Part 1 : the logic deciding a strategy for traversal and unrolling * ***************************************************************************/ template struct assign_traits { public: enum { DstIsAligned = Derived::Flags & AlignedBit, DstHasDirectAccess = Derived::Flags & DirectAccessBit, SrcIsAligned = OtherDerived::Flags & AlignedBit, JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned }; private: enum { InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) : int(Derived::RowsAtCompileTime), InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) : int(Derived::MaxRowsAtCompileTime), MaxSizeAtCompileTime = Derived::SizeAtCompileTime, PacketSize = packet_traits::size }; enum { StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), MightVectorize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 && int(DstIsAligned) && int(SrcIsAligned), MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, so it's only good for large enough sizes. */ MaySliceVectorize = MightVectorize && DstHasDirectAccess && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) /* slice vectorization can be slow, so we only want it if the slices are big, which is indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block in a fixed-size matrix */ }; public: enum { Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(MayLinearize) ? int(LinearTraversal) : int(DefaultTraversal), Vectorized = int(Traversal) == InnerVectorizedTraversal || int(Traversal) == LinearVectorizedTraversal || int(Traversal) == SliceVectorizedTraversal }; private: enum { UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic && int(OtherDerived::CoeffReadCost) != Dynamic && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), MayUnrollInner = int(InnerSize) != Dynamic && int(OtherDerived::CoeffReadCost) != Dynamic && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) }; public: enum { Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) ? ( int(MayUnrollCompletely) ? int(CompleteUnrolling) : int(MayUnrollInner) ? int(InnerUnrolling) : int(NoUnrolling) ) : int(Traversal) == int(LinearVectorizedTraversal) ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) : int(Traversal) == int(LinearTraversal) ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) : int(NoUnrolling) }; #ifdef EIGEN_DEBUG_ASSIGN static void debug() { EIGEN_DEBUG_VAR(DstIsAligned) EIGEN_DEBUG_VAR(SrcIsAligned) EIGEN_DEBUG_VAR(JointAlignment) EIGEN_DEBUG_VAR(InnerSize) EIGEN_DEBUG_VAR(InnerMaxSize) EIGEN_DEBUG_VAR(PacketSize) EIGEN_DEBUG_VAR(StorageOrdersAgree) EIGEN_DEBUG_VAR(MightVectorize) EIGEN_DEBUG_VAR(MayLinearize) EIGEN_DEBUG_VAR(MayInnerVectorize) EIGEN_DEBUG_VAR(MayLinearVectorize) EIGEN_DEBUG_VAR(MaySliceVectorize) EIGEN_DEBUG_VAR(Traversal) EIGEN_DEBUG_VAR(UnrollingLimit) EIGEN_DEBUG_VAR(MayUnrollCompletely) EIGEN_DEBUG_VAR(MayUnrollInner) EIGEN_DEBUG_VAR(Unrolling) } #endif }; /*************************************************************************** * Part 2 : meta-unrollers ***************************************************************************/ /************************ *** Default traversal *** ************************/ template struct assign_DefaultTraversal_CompleteUnrolling { enum { outer = Index / Derived1::InnerSizeAtCompileTime, inner = Index % Derived1::InnerSizeAtCompileTime }; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { dst.copyCoeffByOuterInner(outer, inner, src); assign_DefaultTraversal_CompleteUnrolling::run(dst, src); } }; template struct assign_DefaultTraversal_CompleteUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} }; template struct assign_DefaultTraversal_InnerUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src, int outer) { dst.copyCoeffByOuterInner(outer, Index, src); assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); } }; template struct assign_DefaultTraversal_InnerUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &, int) {} }; /*********************** *** Linear traversal *** ***********************/ template struct assign_LinearTraversal_CompleteUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { dst.copyCoeff(Index, src); assign_LinearTraversal_CompleteUnrolling::run(dst, src); } }; template struct assign_LinearTraversal_CompleteUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} }; /************************** *** Inner vectorization *** **************************/ template struct assign_innervec_CompleteUnrolling { enum { outer = Index / Derived1::InnerSizeAtCompileTime, inner = Index % Derived1::InnerSizeAtCompileTime, JointAlignment = assign_traits::JointAlignment }; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { dst.template copyPacketByOuterInner(outer, inner, src); assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); } }; template struct assign_innervec_CompleteUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} }; template struct assign_innervec_InnerUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src, int outer) { dst.template copyPacketByOuterInner(outer, Index, src); assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); } }; template struct assign_innervec_InnerUnrolling { EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &, int) {} }; /*************************************************************************** * Part 3 : implementation of all cases ***************************************************************************/ template::Traversal, int Unrolling = assign_traits::Unrolling> struct assign_impl; /************************ *** Default traversal *** ************************/ template struct assign_impl { inline static void run(Derived1 &, const Derived2 &) { } }; template struct assign_impl { typedef typename Derived1::Index Index; inline static void run(Derived1 &dst, const Derived2 &src) { const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) for(Index inner = 0; inner < innerSize; ++inner) dst.copyCoeffByOuterInner(outer, inner, src); } }; template struct assign_impl { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { assign_DefaultTraversal_CompleteUnrolling ::run(dst, src); } }; template struct assign_impl { typedef typename Derived1::Index Index; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { const Index outerSize = dst.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) assign_DefaultTraversal_InnerUnrolling ::run(dst, src, outer); } }; /*********************** *** Linear traversal *** ***********************/ template struct assign_impl { typedef typename Derived1::Index Index; inline static void run(Derived1 &dst, const Derived2 &src) { const Index size = dst.size(); for(Index i = 0; i < size; ++i) dst.copyCoeff(i, src); } }; template struct assign_impl { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { assign_LinearTraversal_CompleteUnrolling ::run(dst, src); } }; /************************** *** Inner vectorization *** **************************/ template struct assign_impl { typedef typename Derived1::Index Index; inline static void run(Derived1 &dst, const Derived2 &src) { const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); const Index packetSize = packet_traits::size; for(Index outer = 0; outer < outerSize; ++outer) for(Index inner = 0; inner < innerSize; inner+=packetSize) dst.template copyPacketByOuterInner(outer, inner, src); } }; template struct assign_impl { EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { assign_innervec_CompleteUnrolling ::run(dst, src); } }; template struct assign_impl { typedef typename Derived1::Index Index; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { const Index outerSize = dst.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) assign_innervec_InnerUnrolling ::run(dst, src, outer); } }; /*************************** *** Linear vectorization *** ***************************/ template struct unaligned_assign_impl { template static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} }; template <> struct unaligned_assign_impl { // MSVC must not inline this functions. If it does, it fails to optimize the // packet access path. #ifdef _MSC_VER template static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) #else template static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) #endif { for (typename Derived::Index index = start; index < end; ++index) dst.copyCoeff(index, src); } }; template struct assign_impl { typedef typename Derived1::Index Index; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { const Index size = dst.size(); typedef packet_traits PacketTraits; enum { packetSize = PacketTraits::size, dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , srcAlignment = assign_traits::JointAlignment }; const Index alignedStart = assign_traits::DstIsAligned ? 0 : first_aligned(&dst.coeffRef(0), size); const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); for(Index index = alignedStart; index < alignedEnd; index += packetSize) { dst.template copyPacket(index, src); } unaligned_assign_impl<>::run(src,dst,alignedEnd,size); } }; template struct assign_impl { typedef typename Derived1::Index Index; EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) { enum { size = Derived1::SizeAtCompileTime, packetSize = packet_traits::size, alignedSize = (size/packetSize)*packetSize }; assign_innervec_CompleteUnrolling::run(dst, src); assign_DefaultTraversal_CompleteUnrolling::run(dst, src); } }; /************************** *** Slice vectorization *** ***************************/ template struct assign_impl { typedef typename Derived1::Index Index; inline static void run(Derived1 &dst, const Derived2 &src) { typedef packet_traits PacketTraits; enum { packetSize = PacketTraits::size, alignable = PacketTraits::AlignedOnScalar, dstAlignment = alignable ? Aligned : int(assign_traits::DstIsAligned) , srcAlignment = assign_traits::JointAlignment }; const Index packetAlignedMask = packetSize - 1; const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 : first_aligned(&dst.coeffRef(0,0), innerSize); for(Index outer = 0; outer < outerSize; ++outer) { const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); // do the non-vectorizable part of the assignment for(Index inner = 0; inner(outer, inner, src); // do the non-vectorizable part of the assignment for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); } } }; } // end namespace internal /*************************************************************************** * Part 4 : implementation of DenseBase methods ***************************************************************************/ template template EIGEN_STRONG_INLINE Derived& DenseBase ::lazyAssign(const DenseBase& other) { enum{ SameType = internal::is_same::value }; EIGEN_STATIC_ASSERT_LVALUE(Derived) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) #ifdef EIGEN_DEBUG_ASSIGN internal::assign_traits::debug(); #endif eigen_assert(rows() == other.rows() && cols() == other.cols()); internal::assign_impl::Traversal) : int(InvalidTraversal)>::run(derived(),other.derived()); #ifndef EIGEN_NO_DEBUG checkTransposeAliasing(other.derived()); #endif return derived(); } namespace internal { template struct assign_selector; template struct assign_selector { EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } }; template struct assign_selector { EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } }; template struct assign_selector { EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } }; template struct assign_selector { EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } }; } // end namespace internal template template EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { return internal::assign_selector::run(derived(), other.derived()); } template EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { return internal::assign_selector::run(derived(), other.derived()); } template EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) { return internal::assign_selector::run(derived(), other.derived()); } template template EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) { return internal::assign_selector::run(derived(), other.derived()); } template template EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { other.derived().evalTo(derived()); return derived(); } template template EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { other.evalTo(derived()); return derived(); } #endif // EIGEN_ASSIGN_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/BandMatrix.h000066400000000000000000000326241172143270300217440ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_BANDMATRIX_H #define EIGEN_BANDMATRIX_H namespace internal { template class BandMatrixBase : public EigenBase { public: enum { Flags = internal::traits::Flags, CoeffReadCost = internal::traits::CoeffReadCost, RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, Supers = internal::traits::Supers, Subs = internal::traits::Subs, Options = internal::traits::Options }; typedef typename internal::traits::Scalar Scalar; typedef Matrix DenseMatrixType; typedef typename DenseMatrixType::Index Index; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef EigenBase Base; protected: enum { DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic, SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime) }; public: using Base::derived; using Base::rows; using Base::cols; /** \returns the number of super diagonals */ inline Index supers() const { return derived().supers(); } /** \returns the number of sub diagonals */ inline Index subs() const { return derived().subs(); } /** \returns an expression of the underlying coefficient matrix */ inline const CoefficientsType& coeffs() const { return derived().coeffs(); } /** \returns an expression of the underlying coefficient matrix */ inline CoefficientsType& coeffs() { return derived().coeffs(); } /** \returns a vector expression of the \a i -th column, * only the meaningful part is returned. * \warning the internal storage must be column major. */ inline Block col(Index i) { EIGEN_STATIC_ASSERT((Options&RowMajor)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); Index start = 0; Index len = coeffs().rows(); if (i<=supers()) { start = supers()-i; len = std::min(rows(),std::max(0,coeffs().rows() - (supers()-i))); } else if (i>=rows()-subs()) len = std::max(0,coeffs().rows() - (i + 1 - rows() + subs())); return Block(coeffs(), start, i, len, 1); } /** \returns a vector expression of the main diagonal */ inline Block diagonal() { return Block(coeffs(),supers(),0,1,std::min(rows(),cols())); } /** \returns a vector expression of the main diagonal (const version) */ inline const Block diagonal() const { return Block(coeffs(),supers(),0,1,std::min(rows(),cols())); } template struct DiagonalIntReturnType { enum { ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)), Conjugate = ReturnOpposite && NumTraits::IsComplex, ActualIndex = ReturnOpposite ? -Index : Index, DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic) ? Dynamic : (ActualIndex<0 ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex)) }; typedef Block BuildType; typedef typename internal::conditional,BuildType >, BuildType>::type Type; }; /** \returns a vector expression of the \a N -th sub or super diagonal */ template inline typename DiagonalIntReturnType::Type diagonal() { return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, std::max(0,N), 1, diagonalLength(N)); } /** \returns a vector expression of the \a N -th sub or super diagonal */ template inline const typename DiagonalIntReturnType::Type diagonal() const { return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, std::max(0,N), 1, diagonalLength(N)); } /** \returns a vector expression of the \a i -th sub or super diagonal */ inline Block diagonal(Index i) { eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); } /** \returns a vector expression of the \a i -th sub or super diagonal */ inline const Block diagonal(Index i) const { eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); } template inline void evalTo(Dest& dst) const { dst.resize(rows(),cols()); dst.setZero(); dst.diagonal() = diagonal(); for (Index i=1; i<=supers();++i) dst.diagonal(i) = diagonal(i); for (Index i=1; i<=subs();++i) dst.diagonal(-i) = diagonal(-i); } DenseMatrixType toDenseMatrix() const { DenseMatrixType res(rows(),cols()); evalTo(res); return res; } protected: inline Index diagonalLength(Index i) const { return i<0 ? std::min(cols(),rows()+i) : std::min(rows(),cols()-i); } }; /** * \class BandMatrix * \ingroup Core_Module * * \brief Represents a rectangular matrix with a banded storage * * \param _Scalar Numeric type, i.e. float, double, int * \param Rows Number of rows, or \b Dynamic * \param Cols Number of columns, or \b Dynamic * \param Supers Number of super diagonal * \param Subs Number of sub diagonal * \param _Options A combination of either \b RowMajor or \b ColMajor, and of \b SelfAdjoint * The former controls \ref TopicStorageOrders "storage order", and defaults to * column-major. The latter controls whether the matrix represents a selfadjoint * matrix in which case either Supers of Subs have to be null. * * \sa class TridiagonalMatrix */ template struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; typedef DenseIndex Index; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _Rows, MaxColsAtCompileTime = _Cols, Flags = LvalueBit, Supers = _Supers, Subs = _Subs, Options = _Options, DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic }; typedef Matrix CoefficientsType; }; template class BandMatrix : public BandMatrixBase > { public: typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::Index Index; typedef typename internal::traits::CoefficientsType CoefficientsType; inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { } /** \returns the number of columns */ inline Index rows() const { return m_rows.value(); } /** \returns the number of rows */ inline Index cols() const { return m_coeffs.cols(); } /** \returns the number of super diagonals */ inline Index supers() const { return m_supers.value(); } /** \returns the number of sub diagonals */ inline Index subs() const { return m_subs.value(); } inline const CoefficientsType& coeffs() const { return m_coeffs; } inline CoefficientsType& coeffs() { return m_coeffs; } protected: CoefficientsType m_coeffs; internal::variable_if_dynamic m_rows; internal::variable_if_dynamic m_supers; internal::variable_if_dynamic m_subs; }; template class BandMatrixWrapper; template struct traits > { typedef typename _CoefficientsType::Scalar Scalar; typedef typename _CoefficientsType::StorageKind StorageKind; typedef typename _CoefficientsType::Index Index; enum { CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost, RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _Rows, MaxColsAtCompileTime = _Cols, Flags = LvalueBit, Supers = _Supers, Subs = _Subs, Options = _Options, DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic }; typedef _CoefficientsType CoefficientsType; }; template class BandMatrixWrapper : public BandMatrixBase > { public: typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef typename internal::traits::Index Index; inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows()); } /** \returns the number of columns */ inline Index rows() const { return m_rows.value(); } /** \returns the number of rows */ inline Index cols() const { return m_coeffs.cols(); } /** \returns the number of super diagonals */ inline Index supers() const { return m_supers.value(); } /** \returns the number of sub diagonals */ inline Index subs() const { return m_subs.value(); } inline const CoefficientsType& coeffs() const { return m_coeffs; } protected: const CoefficientsType& m_coeffs; internal::variable_if_dynamic m_rows; internal::variable_if_dynamic m_supers; internal::variable_if_dynamic m_subs; }; /** * \class TridiagonalMatrix * \ingroup Core_Module * * \brief Represents a tridiagonal matrix with a compact banded storage * * \param _Scalar Numeric type, i.e. float, double, int * \param Size Number of rows and cols, or \b Dynamic * \param _Options Can be 0 or \b SelfAdjoint * * \sa class BandMatrix */ template class TridiagonalMatrix : public BandMatrix { typedef BandMatrix Base; typedef typename Base::Index Index; public: TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } inline const typename Base::template DiagonalIntReturnType<1>::Type super() const { return Base::template diagonal<1>(); } inline typename Base::template DiagonalIntReturnType<-1>::Type sub() { return Base::template diagonal<-1>(); } inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const { return Base::template diagonal<-1>(); } protected: }; } // end namespace internal #endif // EIGEN_BANDMATRIX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Block.h000066400000000000000000000341671172143270300207510ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_BLOCK_H #define EIGEN_BLOCK_H /** \class Block * \ingroup Core_Module * * \brief Expression of a fixed-size or dynamic-size block * * \param XprType the type of the expression in which we are taking a block * \param BlockRows the number of rows of the block we are taking at compile time (optional) * \param BlockCols the number of columns of the block we are taking at compile time (optional) * \param _DirectAccessStatus \internal used for partial specialization * * This class represents an expression of either a fixed-size or dynamic-size block. It is the return * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and * most of the time this is the only way it is used. * * However, if you want to directly maniputate block expressions, * for instance if you want to write a function returning such an expression, you * will need to use this class. * * Here is an example illustrating the dynamic case: * \include class_Block.cpp * Output: \verbinclude class_Block.out * * \note Even though this expression has dynamic size, in the case where \a XprType * has fixed size, this expression inherits a fixed maximal size which means that evaluating * it does not cause a dynamic memory allocation. * * Here is an example illustrating the fixed-size case: * \include class_FixedBlock.cpp * Output: \verbinclude class_FixedBlock.out * * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock */ namespace internal { template struct traits > : traits { typedef typename traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename nested::type XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum{ MatrixRows = traits::RowsAtCompileTime, MatrixCols = traits::ColsAtCompileTime, RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows, ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols, MaxRowsAtCompileTime = BlockRows==0 ? 0 : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = BlockCols==0 ? 0 : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), InnerStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), OuterStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) && (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && ((OuterStrideAtCompileTime % packet_traits::size) == 0)) ? AlignedBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | DirectAccessBit | MaskPacketAccessBit | MaskAlignedBit), Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit }; }; } template class Block : public internal::dense_xpr_base >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Block) class InnerIterator; /** Column or Row constructor */ inline Block(XprType& xpr, Index i) : m_xpr(xpr), // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1, // all other cases are invalid. // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), m_blockRows(BlockRows==1 ? 1 : xpr.rows()), m_blockCols(BlockCols==1 ? 1 : xpr.cols()) { eigen_assert( (i>=0) && ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 1 && startRow + BlockRows <= xpr.rows() && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= xpr.cols()); } /** Dynamic-size constructor */ inline Block(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); eigen_assert(startRow >= 0 && blockRows >= 0 && startRow + blockRows <= xpr.rows() && startCol >= 0 && blockCols >= 0 && startCol + blockCols <= xpr.cols()); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) inline Index rows() const { return m_blockRows.value(); } inline Index cols() const { return m_blockCols.value(); } inline Scalar& coeffRef(Index row, Index col) { EIGEN_STATIC_ASSERT_LVALUE(XprType) return m_xpr.const_cast_derived() .coeffRef(row + m_startRow.value(), col + m_startCol.value()); } inline const Scalar& coeffRef(Index row, Index col) const { return m_xpr.derived() .coeffRef(row + m_startRow.value(), col + m_startCol.value()); } EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const { return m_xpr.coeff(row + m_startRow.value(), col + m_startCol.value()); } inline Scalar& coeffRef(Index index) { EIGEN_STATIC_ASSERT_LVALUE(XprType) return m_xpr.const_cast_derived() .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } inline const Scalar& coeffRef(Index index) const { return m_xpr.const_cast_derived() .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } inline const CoeffReturnType coeff(Index index) const { return m_xpr .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } template inline PacketScalar packet(Index row, Index col) const { return m_xpr.template packet (row + m_startRow.value(), col + m_startCol.value()); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_xpr.const_cast_derived().template writePacket (row + m_startRow.value(), col + m_startCol.value(), x); } template inline PacketScalar packet(Index index) const { return m_xpr.template packet (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } template inline void writePacket(Index index, const PacketScalar& x) { m_xpr.const_cast_derived().template writePacket (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), x); } #ifdef EIGEN_PARSED_BY_DOXYGEN /** \sa MapBase::data() */ inline const Scalar* data() const; inline Index innerStride() const; inline Index outerStride() const; #endif protected: const typename XprType::Nested m_xpr; const internal::variable_if_dynamic m_startRow; const internal::variable_if_dynamic m_startCol; const internal::variable_if_dynamic m_blockRows; const internal::variable_if_dynamic m_blockCols; }; /** \internal */ template class Block : public MapBase > { public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) /** Column or Row constructor */ inline Block(XprType& xpr, Index i) : Base(internal::const_cast_ptr(&xpr.coeffRef( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), m_xpr(xpr) { eigen_assert( (i>=0) && ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 1 && startRow + BlockRows <= xpr.rows() && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= xpr.cols()); init(); } /** Dynamic-size constructor */ inline Block(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), m_xpr(xpr) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); eigen_assert(startRow >= 0 && blockRows >= 0 && startRow + blockRows <= xpr.rows() && startCol >= 0 && blockCols >= 0 && startCol + blockCols <= xpr.cols()); init(); } /** \sa MapBase::innerStride() */ inline Index innerStride() const { return internal::traits::HasSameStorageOrderAsXprType ? m_xpr.innerStride() : m_xpr.outerStride(); } /** \sa MapBase::outerStride() */ inline Index outerStride() const { return m_outerStride; } #ifndef __SUNPRO_CC // FIXME sunstudio is not friendly with the above friend... // META-FIXME there is no 'friend' keyword around here. Is this obsolete? protected: #endif #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal used by allowAligned() */ inline Block(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) : Base(data, blockRows, blockCols), m_xpr(xpr) { init(); } #endif protected: void init() { m_outerStride = internal::traits::HasSameStorageOrderAsXprType ? m_xpr.outerStride() : m_xpr.innerStride(); } const typename XprType::Nested m_xpr; int m_outerStride; }; #endif // EIGEN_BLOCK_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/BooleanRedux.h000066400000000000000000000102151172143270300222720ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_ALLANDANY_H #define EIGEN_ALLANDANY_H namespace internal { template struct all_unroller { enum { col = (UnrollCount-1) / Derived::RowsAtCompileTime, row = (UnrollCount-1) % Derived::RowsAtCompileTime }; inline static bool run(const Derived &mat) { return all_unroller::run(mat) && mat.coeff(row, col); } }; template struct all_unroller { inline static bool run(const Derived &mat) { return mat.coeff(0, 0); } }; template struct all_unroller { inline static bool run(const Derived &) { return false; } }; template struct any_unroller { enum { col = (UnrollCount-1) / Derived::RowsAtCompileTime, row = (UnrollCount-1) % Derived::RowsAtCompileTime }; inline static bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); } }; template struct any_unroller { inline static bool run(const Derived &mat) { return mat.coeff(0, 0); } }; template struct any_unroller { inline static bool run(const Derived &) { return false; } }; } // end namespace internal /** \returns true if all coefficients are true * * Example: \include MatrixBase_all.cpp * Output: \verbinclude MatrixBase_all.out * * \sa any(), Cwise::operator<() */ template inline bool DenseBase::all() const { enum { unroll = SizeAtCompileTime != Dynamic && CoeffReadCost != Dynamic && NumTraits::AddCost != Dynamic && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; if(unroll) return internal::all_unroller::run(derived()); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if (!coeff(i, j)) return false; return true; } } /** \returns true if at least one coefficient is true * * \sa all() */ template inline bool DenseBase::any() const { enum { unroll = SizeAtCompileTime != Dynamic && CoeffReadCost != Dynamic && NumTraits::AddCost != Dynamic && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; if(unroll) return internal::any_unroller::run(derived()); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if (coeff(i, j)) return true; return false; } } /** \returns the number of coefficients which evaluate to true * * \sa all(), any() */ template inline typename DenseBase::Index DenseBase::count() const { return derived().template cast().template cast().sum(); } #endif // EIGEN_ALLANDANY_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/CMakeLists.txt000066400000000000000000000003271172143270300222750ustar00rootroot00000000000000FILE(GLOB Eigen_Core_SRCS "*.h") INSTALL(FILES ${Eigen_Core_SRCS} DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core COMPONENT Devel ) ADD_SUBDIRECTORY(products) ADD_SUBDIRECTORY(util) ADD_SUBDIRECTORY(arch) mldemos-0.4.3/_3rdParty/Eigen/src/Core/CommaInitializer.h000066400000000000000000000124721172143270300231520ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_COMMAINITIALIZER_H #define EIGEN_COMMAINITIALIZER_H /** \class CommaInitializer * \ingroup Core_Module * * \brief Helper class used by the comma initializer operator * * This class is internally used to implement the comma initializer feature. It is * the return type of MatrixBase::operator<<, and most of the time this is the only * way it is used. * * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() */ template struct CommaInitializer { typedef typename XprType::Scalar Scalar; typedef typename XprType::Index Index; inline CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { m_xpr.coeffRef(0,0) = s; } template inline CommaInitializer(XprType& xpr, const DenseBase& other) : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) { m_xpr.block(0, 0, other.rows(), other.cols()) = other; } /* inserts a scalar value in the target matrix */ CommaInitializer& operator,(const Scalar& s) { if (m_col==m_xpr.cols()) { m_row+=m_currentBlockRows; m_col = 0; m_currentBlockRows = 1; eigen_assert(m_row CommaInitializer& operator,(const DenseBase& other) { if (m_col==m_xpr.cols()) { m_row+=m_currentBlockRows; m_col = 0; m_currentBlockRows = other.rows(); eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() && "Too many rows passed to comma initializer (operator<<)"); } eigen_assert(m_col (m_row, m_col) = other; else m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other; m_col += other.cols(); return *this; } inline ~CommaInitializer() { eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() && m_col == m_xpr.cols() && "Too few coefficients passed to comma initializer (operator<<)"); } /** \returns the built matrix once all its coefficients have been set. * Calling finished is 100% optional. Its purpose is to write expressions * like this: * \code * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); * \endcode */ inline XprType& finished() { return m_xpr; } XprType& m_xpr; // target expression Index m_row; // current row id Index m_col; // current col id Index m_currentBlockRows; // current block height }; /** \anchor MatrixBaseCommaInitRef * Convenient operator to set the coefficients of a matrix. * * The coefficients must be provided in a row major order and exactly match * the size of the matrix. Otherwise an assertion is raised. * * Example: \include MatrixBase_set.cpp * Output: \verbinclude MatrixBase_set.out * * \sa CommaInitializer::finished(), class CommaInitializer */ template inline CommaInitializer DenseBase::operator<< (const Scalar& s) { return CommaInitializer(*static_cast(this), s); } /** \sa operator<<(const Scalar&) */ template template inline CommaInitializer DenseBase::operator<<(const DenseBase& other) { return CommaInitializer(*static_cast(this), other); } #endif // EIGEN_COMMAINITIALIZER_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/CwiseBinaryOp.h000066400000000000000000000245021172143270300224250ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_CWISE_BINARY_OP_H #define EIGEN_CWISE_BINARY_OP_H /** \class CwiseBinaryOp * \ingroup Core_Module * * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions * * \param BinaryOp template functor implementing the operator * \param Lhs the type of the left-hand side * \param Rhs the type of the right-hand side * * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. * It is the return type of binary operators, by which we mean only those binary operators where * both the left-hand side and the right-hand side are Eigen expressions. * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. * * Most of the time, this is the only way that it is used, so you typically don't have to name * CwiseBinaryOp types explicitly. * * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp */ namespace internal { template struct traits > { // we must not inherit from traits since it has // the potential to cause problems with MSVC typedef typename remove_all::type Ancestor; typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = traits::RowsAtCompileTime, ColsAtCompileTime = traits::ColsAtCompileTime, MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = traits::MaxColsAtCompileTime }; // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), // we still want to handle the case when the result type is different. typedef typename result_of< BinaryOp( typename Lhs::Scalar, typename Rhs::Scalar ) >::type Scalar; typedef typename promote_storage_type::StorageKind, typename traits::StorageKind>::ret StorageKind; typedef typename promote_index_type::Index, typename traits::Index>::type Index; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, RhsCoeffReadCost = _RhsNested::CoeffReadCost, LhsFlags = _LhsNested::Flags, RhsFlags = _RhsNested::Flags, SameType = is_same::value, StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( HereditaryBits | (int(LhsFlags) & int(RhsFlags) & ( AlignedBit | (StorageOrdersAgree ? LinearAccessBit : 0) | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) ) ) ), Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost }; }; } // end namespace internal // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor // that would take two operands of different types. If there were such an example, then this check should be // moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as // currently they take only one typename Scalar template parameter. // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. // So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to // add together a float matrix and a double matrix. #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ EIGEN_STATIC_ASSERT((internal::functor_allows_mixing_real_and_complex::ret \ ? int(internal::is_same::Real, typename NumTraits::Real>::value) \ : int(internal::is_same::value)), \ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) template class CwiseBinaryOpImpl; template class CwiseBinaryOp : internal::no_assignment_operator, public CwiseBinaryOpImpl< BinaryOp, Lhs, Rhs, typename internal::promote_storage_type::StorageKind, typename internal::traits::StorageKind>::ret> { public: typedef typename CwiseBinaryOpImpl< BinaryOp, Lhs, Rhs, typename internal::promote_storage_type::StorageKind, typename internal::traits::StorageKind>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) typedef typename internal::nested::type LhsNested; typedef typename internal::nested::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp()) : m_lhs(lhs), m_rhs(rhs), m_functor(func) { EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); // require the sizes to match EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) eigen_assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols()); } EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::RowsAtCompileTime==Dynamic) return m_rhs.rows(); else return m_lhs.rows(); } EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::ColsAtCompileTime==Dynamic) return m_rhs.cols(); else return m_lhs.cols(); } /** \returns the left hand side nested expression */ const _LhsNested& lhs() const { return m_lhs; } /** \returns the right hand side nested expression */ const _RhsNested& rhs() const { return m_rhs; } /** \returns the functor representing the binary operation */ const BinaryOp& functor() const { return m_functor; } protected: const LhsNested m_lhs; const RhsNested m_rhs; const BinaryOp m_functor; }; template class CwiseBinaryOpImpl : public internal::dense_xpr_base >::type { typedef CwiseBinaryOp Derived; public: typedef typename internal::dense_xpr_base >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return derived().functor()(derived().lhs().coeff(row, col), derived().rhs().coeff(row, col)); } template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { return derived().functor().packetOp(derived().lhs().template packet(row, col), derived().rhs().template packet(row, col)); } EIGEN_STRONG_INLINE const Scalar coeff(Index index) const { return derived().functor()(derived().lhs().coeff(index), derived().rhs().coeff(index)); } template EIGEN_STRONG_INLINE PacketScalar packet(Index index) const { return derived().functor().packetOp(derived().lhs().template packet(index), derived().rhs().template packet(index)); } }; /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } /** replaces \c *this by \c *this + \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); return derived(); } #endif // EIGEN_CWISE_BINARY_OP_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/CwiseNullaryOp.h000066400000000000000000000705501172143270300226330ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_CWISE_NULLARY_OP_H #define EIGEN_CWISE_NULLARY_OP_H /** \class CwiseNullaryOp * \ingroup Core_Module * * \brief Generic expression of a matrix where all coefficients are defined by a functor * * \param NullaryOp template functor implementing the operator * \param PlainObjectType the underlying plain matrix/array type * * This class represents an expression of a generic nullary operator. * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, * and most of the time this is the only way it is used. * * However, if you want to write a function returning such an expression, you * will need to use this class. * * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr() */ namespace internal { template struct traits > : traits { enum { Flags = (traits::Flags & ( HereditaryBits | (functor_has_linear_access::ret ? LinearAccessBit : 0) | (functor_traits::PacketAccess ? PacketAccessBit : 0))) | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), CoeffReadCost = functor_traits::Cost }; }; } template class CwiseNullaryOp : internal::no_assignment_operator, public internal::dense_xpr_base< CwiseNullaryOp >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) : m_rows(rows), m_cols(cols), m_functor(func) { eigen_assert(rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); } EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } EIGEN_STRONG_INLINE const Scalar coeff(Index rows, Index cols) const { return m_functor(rows, cols); } template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { return m_functor.packetOp(row, col); } EIGEN_STRONG_INLINE const Scalar coeff(Index index) const { return m_functor(index); } template EIGEN_STRONG_INLINE PacketScalar packet(Index index) const { return m_functor.packetOp(index); } protected: const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; const NullaryOp m_functor; }; /** \returns an expression of a matrix defined by a custom functor \a func * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template template EIGEN_STRONG_INLINE const CwiseNullaryOp DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) { return CwiseNullaryOp(rows, cols, func); } /** \returns an expression of a matrix defined by a custom functor \a func * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template template EIGEN_STRONG_INLINE const CwiseNullaryOp DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); else return CwiseNullaryOp(size, 1, func); } /** \returns an expression of a matrix defined by a custom functor \a func * * This variant is only for fixed-size DenseBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template template EIGEN_STRONG_INLINE const CwiseNullaryOp DenseBase::NullaryExpr(const CustomNullaryOp& func) { return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); } /** \returns an expression of a constant matrix of value \a value * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this DenseBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(Index rows, Index cols, const Scalar& value) { return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value * * The parameter \a size is the size of the returned vector. * Must be compatible with this DenseBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(Index size, const Scalar& value) { return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value * * This variant is only for fixed-size DenseBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(const Scalar& value) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); } /** * \brief Sets a linearly space vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * This particular version of LinSpaced() uses sequential access, i.e. vector access is * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization * and yields faster code than the random access version. * * \only_for_vectors * * Example: \include DenseBase_LinSpaced_seq.cpp * Output: \verbinclude DenseBase_LinSpaced_seq.out * * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** * \copydoc DenseBase::LinSpaced(Sequential_t, Index, const Scalar&, const Scalar&) * Special version for fixed size types which does not require the size parameter. */ template EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** * \brief Sets a linearly space vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * * \only_for_vectors * * Example: \include DenseBase_LinSpaced.cpp * Output: \verbinclude DenseBase_LinSpaced.out * * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Sequential_t,Index,const Scalar&,const Scalar&,Index), CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&) * Special version for fixed size types which does not require the size parameter. */ template EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ template bool DenseBase::isApproxToConstant (const Scalar& value, RealScalar prec) const { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if(!internal::isApprox(this->coeff(i, j), value, prec)) return false; return true; } /** This is just an alias for isApproxToConstant(). * * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ template bool DenseBase::isConstant (const Scalar& value, RealScalar prec) const { return isApproxToConstant(value, prec); } /** Alias for setConstant(): sets all coefficients in this expression to \a value. * * \sa setConstant(), Constant(), class CwiseNullaryOp */ template EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& value) { setConstant(value); } /** Sets all coefficients in this expression to \a value. * * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() */ template EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& value) { return derived() = Constant(rows(), cols(), value); } /** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. * * \only_for_vectors * * Example: \include Matrix_setConstant_int.cpp * Output: \verbinclude Matrix_setConstant_int.out * * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setConstant(Index size, const Scalar& value) { resize(size); return setConstant(value); } /** Resizes to the given size, and sets all coefficients in this expression to the given \a value. * * \param rows the new number of rows * \param cols the new number of columns * \param value the value to which all coefficients are set * * Example: \include Matrix_setConstant_int_int.cpp * Output: \verbinclude Matrix_setConstant_int_int.out * * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& value) { resize(rows, cols); return setConstant(value); } /** * \brief Sets a linearly space vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * * \only_for_vectors * * Example: \include DenseBase_setLinSpaced.cpp * Output: \verbinclude DenseBase_setLinSpaced.out * * \sa CwiseNullaryOp */ template EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return derived() = Derived::NullaryExpr(size, internal::linspaced_op(low,high,size)); } // zero: /** \returns an expression of a zero matrix. * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * Example: \include MatrixBase_zero_int_int.cpp * Output: \verbinclude MatrixBase_zero_int_int.out * * \sa Zero(), Zero(Index) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero(Index rows, Index cols) { return Constant(rows, cols, Scalar(0)); } /** \returns an expression of a zero vector. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * Example: \include MatrixBase_zero_int.cpp * Output: \verbinclude MatrixBase_zero_int.out * * \sa Zero(), Zero(Index,Index) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero(Index size) { return Constant(size, Scalar(0)); } /** \returns an expression of a fixed-size zero matrix or vector. * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_zero.cpp * Output: \verbinclude MatrixBase_zero.out * * \sa Zero(Index), Zero(Index,Index) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero() { return Constant(Scalar(0)); } /** \returns true if *this is approximately equal to the zero matrix, * within the precision given by \a prec. * * Example: \include MatrixBase_isZero.cpp * Output: \verbinclude MatrixBase_isZero.out * * \sa class CwiseNullaryOp, Zero() */ template bool DenseBase::isZero(RealScalar prec) const { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) return false; return true; } /** Sets all coefficients in this expression to zero. * * Example: \include MatrixBase_setZero.cpp * Output: \verbinclude MatrixBase_setZero.out * * \sa class CwiseNullaryOp, Zero() */ template EIGEN_STRONG_INLINE Derived& DenseBase::setZero() { return setConstant(Scalar(0)); } /** Resizes to the given \a size, and sets all coefficients in this expression to zero. * * \only_for_vectors * * Example: \include Matrix_setZero_int.cpp * Output: \verbinclude Matrix_setZero_int.out * * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setZero(Index size) { resize(size); return setConstant(Scalar(0)); } /** Resizes to the given size, and sets all coefficients in this expression to zero. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setZero_int_int.cpp * Output: \verbinclude Matrix_setZero_int_int.out * * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setZero(Index rows, Index cols) { resize(rows, cols); return setConstant(Scalar(0)); } // ones: /** \returns an expression of a matrix where all coefficients equal one. * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used * instead. * * Example: \include MatrixBase_ones_int_int.cpp * Output: \verbinclude MatrixBase_ones_int_int.out * * \sa Ones(), Ones(Index), isOnes(), class Ones */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones(Index rows, Index cols) { return Constant(rows, cols, Scalar(1)); } /** \returns an expression of a vector where all coefficients equal one. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Ones() should be used * instead. * * Example: \include MatrixBase_ones_int.cpp * Output: \verbinclude MatrixBase_ones_int.out * * \sa Ones(), Ones(Index,Index), isOnes(), class Ones */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones(Index size) { return Constant(size, Scalar(1)); } /** \returns an expression of a fixed-size matrix or vector where all coefficients equal one. * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_ones.cpp * Output: \verbinclude MatrixBase_ones.out * * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones() { return Constant(Scalar(1)); } /** \returns true if *this is approximately equal to the matrix where all coefficients * are equal to 1, within the precision given by \a prec. * * Example: \include MatrixBase_isOnes.cpp * Output: \verbinclude MatrixBase_isOnes.out * * \sa class CwiseNullaryOp, Ones() */ template bool DenseBase::isOnes (RealScalar prec) const { return isApproxToConstant(Scalar(1), prec); } /** Sets all coefficients in this expression to one. * * Example: \include MatrixBase_setOnes.cpp * Output: \verbinclude MatrixBase_setOnes.out * * \sa class CwiseNullaryOp, Ones() */ template EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() { return setConstant(Scalar(1)); } /** Resizes to the given \a size, and sets all coefficients in this expression to one. * * \only_for_vectors * * Example: \include Matrix_setOnes_int.cpp * Output: \verbinclude Matrix_setOnes_int.out * * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setOnes(Index size) { resize(size); return setConstant(Scalar(1)); } /** Resizes to the given size, and sets all coefficients in this expression to one. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setOnes_int_int.cpp * Output: \verbinclude Matrix_setOnes_int_int.out * * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setOnes(Index rows, Index cols) { resize(rows, cols); return setConstant(Scalar(1)); } // Identity: /** \returns an expression of the identity matrix (not necessarily square). * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used * instead. * * Example: \include MatrixBase_identity_int_int.cpp * Output: \verbinclude MatrixBase_identity_int_int.out * * \sa Identity(), setIdentity(), isIdentity() */ template EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType MatrixBase::Identity(Index rows, Index cols) { return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); } /** \returns an expression of the identity matrix (not necessarily square). * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variant taking size arguments. * * Example: \include MatrixBase_identity.cpp * Output: \verbinclude MatrixBase_identity.out * * \sa Identity(Index,Index), setIdentity(), isIdentity() */ template EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType MatrixBase::Identity() { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return MatrixBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op()); } /** \returns true if *this is approximately equal to the identity matrix * (not necessarily square), * within the precision given by \a prec. * * Example: \include MatrixBase_isIdentity.cpp * Output: \verbinclude MatrixBase_isIdentity.out * * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity() */ template bool MatrixBase::isIdentity (RealScalar prec) const { for(Index j = 0; j < cols(); ++j) { for(Index i = 0; i < rows(); ++i) { if(i == j) { if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) return false; } else { if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) return false; } } } return true; } namespace internal { template=16)> struct setIdentity_impl { static EIGEN_STRONG_INLINE Derived& run(Derived& m) { return m = Derived::Identity(m.rows(), m.cols()); } }; template struct setIdentity_impl { typedef typename Derived::Index Index; static EIGEN_STRONG_INLINE Derived& run(Derived& m) { m.setZero(); const Index size = std::min(m.rows(), m.cols()); for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); return m; } }; } // end namespace internal /** Writes the identity expression (not necessarily square) into *this. * * Example: \include MatrixBase_setIdentity.cpp * Output: \verbinclude MatrixBase_setIdentity.out * * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() */ template EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() { return internal::setIdentity_impl::run(derived()); } /** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setIdentity_int_int.cpp * Output: \verbinclude Matrix_setIdentity_int_int.out * * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() */ template EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) { derived().resize(rows, cols); return setIdentity(); } /** \returns an expression of the i-th unit (basis) vector. * * \only_for_vectors * * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index size, Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(size,size), i); } /** \returns an expression of the i-th unit (basis) vector. * * \only_for_vectors * * This variant is for fixed-size vector only. * * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(),i); } /** \returns an expression of the X axis unit vector (1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() { return Derived::Unit(0); } /** \returns an expression of the Y axis unit vector (0,1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() { return Derived::Unit(1); } /** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() { return Derived::Unit(2); } /** \returns an expression of the W axis unit vector (0,0,0,1) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() { return Derived::Unit(3); } #endif // EIGEN_CWISE_NULLARY_OP_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/CwiseUnaryOp.h000066400000000000000000000124651172143270300223040ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_CWISE_UNARY_OP_H #define EIGEN_CWISE_UNARY_OP_H /** \class CwiseUnaryOp * \ingroup Core_Module * * \brief Generic expression where a coefficient-wise unary operator is applied to an expression * * \param UnaryOp template functor implementing the operator * \param XprType the type of the expression to which we are applying the unary operator * * This class represents an expression where a unary operator is applied to an expression. * It is the return type of all operations taking exactly 1 input expression, regardless of the * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix * is considered unary, because only the right-hand side is an expression, and its * return type is a specialization of CwiseUnaryOp. * * Most of the time, this is the only way that it is used, so you typically don't have to name * CwiseUnaryOp types explicitly. * * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp */ namespace internal { template struct traits > : traits { typedef typename result_of< UnaryOp(typename XprType::Scalar) >::type Scalar; typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { Flags = _XprTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost }; }; } template class CwiseUnaryOpImpl; template class CwiseUnaryOp : internal::no_assignment_operator, public CwiseUnaryOpImpl::StorageKind> { public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } /** \returns the functor representing the unary operation */ const UnaryOp& functor() const { return m_functor; } /** \returns the nested expression */ const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \returns the nested expression */ typename internal::remove_all::type& nestedExpression() { return m_xpr.const_cast_derived(); } protected: const typename XprType::Nested m_xpr; const UnaryOp m_functor; }; // This is the generic implementation for dense storage. // It can be used for any expression types implementing the dense concept. template class CwiseUnaryOpImpl : public internal::dense_xpr_base >::type { public: typedef CwiseUnaryOp Derived; typedef typename internal::dense_xpr_base >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return derived().functor()(derived().nestedExpression().coeff(row, col)); } template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { return derived().functor().packetOp(derived().nestedExpression().template packet(row, col)); } EIGEN_STRONG_INLINE const Scalar coeff(Index index) const { return derived().functor()(derived().nestedExpression().coeff(index)); } template EIGEN_STRONG_INLINE PacketScalar packet(Index index) const { return derived().functor().packetOp(derived().nestedExpression().template packet(index)); } }; #endif // EIGEN_CWISE_UNARY_OP_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/CwiseUnaryView.h000066400000000000000000000133051172143270300226320ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_CWISE_UNARY_VIEW_H #define EIGEN_CWISE_UNARY_VIEW_H /** \class CwiseUnaryView * \ingroup Core_Module * * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector * * \param ViewOp template functor implementing the view * \param MatrixType the type of the matrix we are applying the unary operator * * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. * It is the return type of real() and imag(), and most of the time this is the only way it is used. * * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp */ namespace internal { template struct traits > : traits { typedef typename result_of< ViewOp(typename traits::Scalar) >::type Scalar; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic ? int(Dynamic) : int(MatrixTypeInnerStride) * int(sizeof(typename traits::Scalar) / sizeof(Scalar)), OuterStrideAtCompileTime = outer_stride_at_compile_time::ret }; }; } template class CwiseUnaryViewImpl; template class CwiseUnaryView : internal::no_assignment_operator, public CwiseUnaryViewImpl::StorageKind> { public: typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } /** \returns the functor representing unary operation */ const ViewOp& functor() const { return m_functor; } /** \returns the nested expression */ const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } /** \returns the nested expression */ typename internal::remove_all::type& nestedExpression() { return m_matrix.const_cast_derived(); } protected: // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC const typename internal::nested::type m_matrix; ViewOp m_functor; }; template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type { public: typedef CwiseUnaryView Derived; typedef typename internal::dense_xpr_base< CwiseUnaryView >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } inline Index outerStride() const { return derived().nestedExpression().outerStride(); } EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return derived().functor()(derived().nestedExpression().coeff(row, col)); } EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return derived().functor()(derived().nestedExpression().coeff(index)); } EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); } EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); } }; #endif // EIGEN_CWISE_UNARY_VIEW_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/DenseBase.h000066400000000000000000000573251172143270300215510ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DENSEBASE_H #define EIGEN_DENSEBASE_H /** \class DenseBase * \ingroup Core_Module * * \brief Base class for all dense matrices, vectors, and arrays * * This class is the base that is inherited by all dense objects (matrix, vector, arrays, * and related expression types). The common Eigen API for dense objects is contained in this class. * * \tparam Derived is the derived type, e.g., a matrix type or an expression. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. * * \sa \ref TopicClassHierarchy */ template class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN : public internal::special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real> #else : public DenseCoeffsBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: using internal::special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real>::operator*; class InnerIterator; typedef typename internal::traits::StorageKind StorageKind; /** \brief The type of indices * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. * \sa \ref TopicPreprocessorDirectives. */ typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseCoeffsBase Base; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::rowIndexByOuterInner; using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; using Base::packet; using Base::packetByOuterInner; using Base::writePacket; using Base::writePacketByOuterInner; using Base::coeffRef; using Base::coeffRefByOuterInner; using Base::copyCoeff; using Base::copyCoeffByOuterInner; using Base::copyPacket; using Base::copyPacketByOuterInner; using Base::operator(); using Base::operator[]; using Base::x; using Base::y; using Base::z; using Base::w; using Base::stride; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; typedef typename Base::CoeffReturnType CoeffReturnType; enum { RowsAtCompileTime = internal::traits::RowsAtCompileTime, /**< The number of rows at compile-time. This is just a copy of the value provided * by the \a Derived type. If a value is not known at compile-time, * it is set to the \a Dynamic constant. * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ ColsAtCompileTime = internal::traits::ColsAtCompileTime, /**< The number of columns at compile-time. This is just a copy of the value provided * by the \a Derived type. If a value is not known at compile-time, * it is set to the \a Dynamic constant. * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, internal::traits::ColsAtCompileTime>::ret), /**< This is equal to the number of coefficients, i.e. the number of * rows times the number of columns, or to \a Dynamic if this is not * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, /**< This value is equal to the maximum possible number of rows that this expression * might have. If this expression might have an arbitrarily high number of rows, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime */ MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, /**< This value is equal to the maximum possible number of columns that this expression * might have. If this expression might have an arbitrarily high number of columns, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime */ MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime>::ret), /**< This value is equal to the maximum possible number of coefficients that this expression * might have. If this expression might have an arbitrarily high number of coefficients, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime */ IsVectorAtCompileTime = internal::traits::MaxRowsAtCompileTime == 1 || internal::traits::MaxColsAtCompileTime == 1, /**< This is set to true if either the number of rows or the number of * columns is known at compile-time to be equal to 1. Indeed, in that case, * we are dealing with a column-vector (if there is only one column) or with * a row-vector (if there is only one row). */ Flags = internal::traits::Flags, /**< This stores expression \ref flags flags which may or may not be inherited by new expressions * constructed from this one. See the \ref flags "list of flags". */ IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */ InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? SizeAtCompileTime : int(IsRowMajor) ? ColsAtCompileTime : RowsAtCompileTime, CoeffReadCost = internal::traits::CoeffReadCost, /**< This is a rough measure of how expensive it is to read one coefficient from * this expression. */ InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; enum { ThisConstantIsPrivateInPlainObjectBase }; /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ inline Index nonZeros() const { return size(); } /** \returns true if either the number of rows or the number of columns is equal to 1. * In other words, this function returns * \code rows()==1 || cols()==1 \endcode * \sa rows(), cols(), IsVectorAtCompileTime. */ /** \returns the outer size. * * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a * column-major matrix, and the number of rows for a row-major matrix. */ Index outerSize() const { return IsVectorAtCompileTime ? 1 : int(IsRowMajor) ? this->rows() : this->cols(); } /** \returns the inner size. * * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a * column-major matrix, and the number of columns for a row-major matrix. */ Index innerSize() const { return IsVectorAtCompileTime ? this->size() : int(IsRowMajor) ? this->cols() : this->rows(); } /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ void resize(Index size) { EIGEN_ONLY_USED_FOR_DEBUG(size); eigen_assert(size == this->size() && "DenseBase::resize() does not actually allow to resize."); } /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ void resize(Index rows, Index cols) { EIGEN_ONLY_USED_FOR_DEBUG(rows); EIGEN_ONLY_USED_FOR_DEBUG(cols); eigen_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Derived> ConstantReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this. \returns a reference to *this. */ template Derived& operator=(const DenseBase& other); /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ Derived& operator=(const DenseBase& other); template Derived& operator=(const EigenBase &other); template Derived& operator+=(const EigenBase &other); template Derived& operator-=(const EigenBase &other); template Derived& operator=(const ReturnByValue& func); #ifndef EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ template Derived& lazyAssign(const DenseBase& other); #endif // not EIGEN_PARSED_BY_DOXYGEN CommaInitializer operator<< (const Scalar& s); template const Flagged flagged() const; template CommaInitializer operator<< (const DenseBase& other); Eigen::Transpose transpose(); typedef const Transpose ConstTransposeReturnType; ConstTransposeReturnType transpose() const; void transposeInPlace(); #ifndef EIGEN_NO_DEBUG protected: template void checkTransposeAliasing(const OtherDerived& other) const; public: #endif typedef VectorBlock SegmentReturnType; typedef const VectorBlock ConstSegmentReturnType; template struct FixedSegmentReturnType { typedef VectorBlock Type; }; template struct ConstFixedSegmentReturnType { typedef const VectorBlock Type; }; // Note: The "DenseBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations. SegmentReturnType segment(Index start, Index size); typename DenseBase::ConstSegmentReturnType segment(Index start, Index size) const; SegmentReturnType head(Index size); typename DenseBase::ConstSegmentReturnType head(Index size) const; SegmentReturnType tail(Index size); typename DenseBase::ConstSegmentReturnType tail(Index size) const; template typename FixedSegmentReturnType::Type head(); template typename ConstFixedSegmentReturnType::Type head() const; template typename FixedSegmentReturnType::Type tail(); template typename ConstFixedSegmentReturnType::Type tail() const; template typename FixedSegmentReturnType::Type segment(Index start); template typename ConstFixedSegmentReturnType::Type segment(Index start) const; static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); static const ConstantReturnType Constant(Index size, const Scalar& value); static const ConstantReturnType Constant(const Scalar& value); static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); static const RandomAccessLinSpacedReturnType LinSpaced(Index size, const Scalar& low, const Scalar& high); static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); static const RandomAccessLinSpacedReturnType LinSpaced(const Scalar& low, const Scalar& high); template static const CwiseNullaryOp NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); template static const CwiseNullaryOp NullaryExpr(Index size, const CustomNullaryOp& func); template static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); static const ConstantReturnType Zero(Index rows, Index cols); static const ConstantReturnType Zero(Index size); static const ConstantReturnType Zero(); static const ConstantReturnType Ones(Index rows, Index cols); static const ConstantReturnType Ones(Index size); static const ConstantReturnType Ones(); void fill(const Scalar& value); Derived& setConstant(const Scalar& value); Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); Derived& setLinSpaced(const Scalar& low, const Scalar& high); Derived& setZero(); Derived& setOnes(); Derived& setRandom(); template bool isApprox(const DenseBase& other, RealScalar prec = NumTraits::dummy_precision()) const; bool isMuchSmallerThan(const RealScalar& other, RealScalar prec = NumTraits::dummy_precision()) const; template bool isMuchSmallerThan(const DenseBase& other, RealScalar prec = NumTraits::dummy_precision()) const; bool isApproxToConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; bool isConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; bool isZero(RealScalar prec = NumTraits::dummy_precision()) const; bool isOnes(RealScalar prec = NumTraits::dummy_precision()) const; inline Derived& operator*=(const Scalar& other); inline Derived& operator/=(const Scalar& other); /** \returns the matrix or vector obtained by evaluating this expression. * * Notice that in the case of a plain matrix or vector (not an expression) this function just returns * a const reference, in order to avoid a useless copy. */ EIGEN_STRONG_INLINE const typename internal::eval::type eval() const { // Even though MSVC does not honor strong inlining when the return type // is a dynamic matrix, we desperately need strong inlining for fixed // size types on MSVC. return typename internal::eval::type(derived()); } /** swaps *this with the expression \a other. * */ template void swap(const DenseBase& other, int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) { SwapWrapper(derived()).lazyAssign(other.derived()); } /** swaps *this with the matrix or array \a other. * */ template void swap(PlainObjectBase& other) { SwapWrapper(derived()).lazyAssign(other.derived()); } inline const NestByValue nestByValue() const; inline const ForceAlignedAccess forceAlignedAccess() const; inline ForceAlignedAccess forceAlignedAccess(); template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); Scalar sum() const; Scalar mean() const; Scalar trace() const; Scalar prod() const; typename internal::traits::Scalar minCoeff() const; typename internal::traits::Scalar maxCoeff() const; template typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; template typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; template typename internal::traits::Scalar minCoeff(IndexType* index) const; template typename internal::traits::Scalar maxCoeff(IndexType* index) const; template typename internal::result_of::Scalar)>::type redux(const BinaryOp& func) const; template void visit(Visitor& func) const; inline const WithFormat format(const IOFormat& fmt) const; /** \returns the unique coefficient of a 1x1 expression */ CoeffReturnType value() const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeff(0,0); } /////////// Array module /////////// bool all(void) const; bool any(void) const; Index count() const; typedef VectorwiseOp RowwiseReturnType; typedef const VectorwiseOp ConstRowwiseReturnType; typedef VectorwiseOp ColwiseReturnType; typedef const VectorwiseOp ConstColwiseReturnType; ConstRowwiseReturnType rowwise() const; RowwiseReturnType rowwise(); ConstColwiseReturnType colwise() const; ColwiseReturnType colwise(); static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); static const CwiseNullaryOp,Derived> Random(Index size); static const CwiseNullaryOp,Derived> Random(); template const Select select(const DenseBase& thenMatrix, const DenseBase& elseMatrix) const; template inline const Select select(const DenseBase& thenMatrix, typename ThenDerived::Scalar elseScalar) const; template inline const Select select(typename ElseDerived::Scalar thenScalar, const DenseBase& elseMatrix) const; template RealScalar lpNorm() const; template const Replicate replicate() const; const Replicate replicate(Index rowFacor,Index colFactor) const; typedef Reverse ReverseReturnType; typedef const Reverse ConstReverseReturnType; ReverseReturnType reverse(); ConstReverseReturnType reverse() const; void reverseInPlace(); #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase # include "../plugins/BlockMethods.h" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS #ifdef EIGEN2_SUPPORT Block corner(CornerType type, Index cRows, Index cCols); const Block corner(CornerType type, Index cRows, Index cCols) const; template Block corner(CornerType type); template const Block corner(CornerType type) const; #endif // EIGEN2_SUPPORT // disable the use of evalTo for dense objects with a nice compilation error template inline void evalTo(Dest& ) const { EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); } protected: /** Default constructor. Do nothing. */ DenseBase() { /* Just checks for self-consistency of the flags. * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down */ #ifdef EIGEN_INTERNAL_DEBUGGING EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor)) && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))), INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION) #endif } private: explicit DenseBase(int); DenseBase(int,int); template explicit DenseBase(const DenseBase&); }; #endif // EIGEN_DENSEBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/DenseCoeffsBase.h000066400000000000000000000672351172143270300227000ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DENSECOEFFSBASE_H #define EIGEN_DENSECOEFFSBASE_H namespace internal { template struct add_const_on_value_type_if_arithmetic { typedef typename conditional::value, T, typename add_const_on_value_type::type>::type type; }; } /** \brief Base class providing read-only coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam ReadOnlyAccessors Constant indicating read-only access * * This class defines the \c operator() \c const function and friends, which can be used to read specific * entries of a matrix or array. * * \sa DenseCoeffsBase, DenseCoeffsBase, * \ref TopicClassHierarchy */ template class DenseCoeffsBase : public EigenBase { public: typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; // Explanation for this CoeffReturnType typedef. // - This is the return type of the coeff() method. // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value). // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is // not possible, since the underlying expressions might not offer a valid address the reference could be referring to. typedef typename internal::conditional::Flags&LvalueBit), const Scalar&, typename internal::conditional::value, Scalar, const Scalar>::type >::type CoeffReturnType; typedef typename internal::add_const_on_value_type_if_arithmetic< typename internal::packet_traits::type >::type PacketReturnType; typedef EigenBase Base; using Base::rows; using Base::cols; using Base::size; using Base::derived; EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 : int(Derived::ColsAtCompileTime) == 1 ? inner : int(Derived::Flags)&RowMajorBit ? outer : inner; } EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const { return int(Derived::ColsAtCompileTime) == 1 ? 0 : int(Derived::RowsAtCompileTime) == 1 ? inner : int(Derived::Flags)&RowMajorBit ? inner : outer; } /** Short version: don't use this function, use * \link operator()(Index,Index) const \endlink instead. * * Long version: this function is similar to * \link operator()(Index,Index) const \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator()(Index,Index) const \endlink. * * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const */ EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return derived().coeff(row, col); } EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return coeff(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \returns the coefficient at given the given row and column. * * \sa operator()(Index,Index), operator[](Index) */ EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return derived().coeff(row, col); } /** Short version: don't use this function, use * \link operator[](Index) const \endlink instead. * * Long version: this function is similar to * \link operator[](Index) const \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameter \a index is in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator[](Index) const \endlink. * * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const */ EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { eigen_internal_assert(index >= 0 && index < size()); return derived().coeff(index); } /** \returns the coefficient at given index. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, * z() const, w() const */ EIGEN_STRONG_INLINE CoeffReturnType operator[](Index index) const { #ifndef EIGEN2_SUPPORT EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) #endif eigen_assert(index >= 0 && index < size()); return derived().coeff(index); } /** \returns the coefficient at given index. * * This is synonymous to operator[](Index) const. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, * z() const, w() const */ EIGEN_STRONG_INLINE CoeffReturnType operator()(Index index) const { eigen_assert(index >= 0 && index < size()); return derived().coeff(index); } /** equivalent to operator[](0). */ EIGEN_STRONG_INLINE CoeffReturnType x() const { return (*this)[0]; } /** equivalent to operator[](1). */ EIGEN_STRONG_INLINE CoeffReturnType y() const { return (*this)[1]; } /** equivalent to operator[](2). */ EIGEN_STRONG_INLINE CoeffReturnType z() const { return (*this)[2]; } /** equivalent to operator[](3). */ EIGEN_STRONG_INLINE CoeffReturnType w() const { return (*this)[3]; } /** \internal * \returns the packet of coefficients starting at the given row and column. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit. * * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return derived().template packet(row,col); } /** \internal */ template EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const { return packet(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \internal * \returns the packet of coefficients starting at the given index. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit and the LinearAccessBit. * * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { eigen_internal_assert(index >= 0 && index < size()); return derived().template packet(index); } protected: // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase. // But some methods are only available in the DirectAccess case. // So we add dummy methods here with these names, so that "using... " doesn't fail. // It's not private so that the child class DenseBase can access them, and it's not public // either since it's an implementation detail, so has to be protected. void coeffRef(); void coeffRefByOuterInner(); void writePacket(); void writePacketByOuterInner(); void copyCoeff(); void copyCoeffByOuterInner(); void copyPacket(); void copyPacketByOuterInner(); void stride(); void innerStride(); void outerStride(); void rowStride(); void colStride(); }; /** \brief Base class providing read/write coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam WriteAccessors Constant indicating read/write access * * This class defines the non-const \c operator() function and friends, which can be used to write specific * entries of a matrix or array. This class inherits DenseCoeffsBase which * defines the const variant for reading specific entries. * * \sa DenseCoeffsBase, \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; using Base::coeff; using Base::rows; using Base::cols; using Base::size; using Base::derived; using Base::rowIndexByOuterInner; using Base::colIndexByOuterInner; using Base::operator[]; using Base::operator(); using Base::x; using Base::y; using Base::z; using Base::w; /** Short version: don't use this function, use * \link operator()(Index,Index) \endlink instead. * * Long version: this function is similar to * \link operator()(Index,Index) \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator()(Index,Index) \endlink. * * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index) */ EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return derived().coeffRef(row, col); } EIGEN_STRONG_INLINE Scalar& coeffRefByOuterInner(Index outer, Index inner) { return coeffRef(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \returns a reference to the coefficient at given the given row and column. * * \sa operator[](Index) */ EIGEN_STRONG_INLINE Scalar& operator()(Index row, Index col) { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return derived().coeffRef(row, col); } /** Short version: don't use this function, use * \link operator[](Index) \endlink instead. * * Long version: this function is similar to * \link operator[](Index) \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator[](Index) \endlink. * * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index) */ EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { eigen_internal_assert(index >= 0 && index < size()); return derived().coeffRef(index); } /** \returns a reference to the coefficient at given index. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() */ EIGEN_STRONG_INLINE Scalar& operator[](Index index) { #ifndef EIGEN2_SUPPORT EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) #endif eigen_assert(index >= 0 && index < size()); return derived().coeffRef(index); } /** \returns a reference to the coefficient at given index. * * This is synonymous to operator[](Index). * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() */ EIGEN_STRONG_INLINE Scalar& operator()(Index index) { eigen_assert(index >= 0 && index < size()); return derived().coeffRef(index); } /** equivalent to operator[](0). */ EIGEN_STRONG_INLINE Scalar& x() { return (*this)[0]; } /** equivalent to operator[](1). */ EIGEN_STRONG_INLINE Scalar& y() { return (*this)[1]; } /** equivalent to operator[](2). */ EIGEN_STRONG_INLINE Scalar& z() { return (*this)[2]; } /** equivalent to operator[](3). */ EIGEN_STRONG_INLINE Scalar& w() { return (*this)[3]; } /** \internal * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit. * * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE void writePacket (Index row, Index col, const typename internal::packet_traits::type& x) { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); derived().template writePacket(row,col,x); } /** \internal */ template EIGEN_STRONG_INLINE void writePacketByOuterInner (Index outer, Index inner, const typename internal::packet_traits::type& x) { writePacket(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner), x); } /** \internal * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit and the LinearAccessBit. * * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE void writePacket (Index index, const typename internal::packet_traits::type& x) { eigen_internal_assert(index >= 0 && index < size()); derived().template writePacket(index,x); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Copies the coefficient at position (row,col) of other into *this. * * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code * with usual assignments. * * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. */ template EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); derived().coeffRef(row, col) = other.derived().coeff(row, col); } /** \internal Copies the coefficient at the given index of other into *this. * * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code * with usual assignments. * * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. */ template EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) { eigen_internal_assert(index >= 0 && index < size()); derived().coeffRef(index) = other.derived().coeff(index); } template EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) { const Index row = rowIndexByOuterInner(outer,inner); const Index col = colIndexByOuterInner(outer,inner); // derived() is important here: copyCoeff() may be reimplemented in Derived! derived().copyCoeff(row, col, other); } /** \internal Copies the packet at position (row,col) of other into *this. * * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code * with usual assignments. * * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. */ template EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); derived().template writePacket(row, col, other.derived().template packet(row, col)); } /** \internal Copies the packet at the given index of other into *this. * * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code * with usual assignments. * * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. */ template EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) { eigen_internal_assert(index >= 0 && index < size()); derived().template writePacket(index, other.derived().template packet(index)); } /** \internal */ template EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) { const Index row = rowIndexByOuterInner(outer,inner); const Index col = colIndexByOuterInner(outer,inner); // derived() is important here: copyCoeff() may be reimplemented in Derived! derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); } #endif }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam DirectAccessors Constant indicating direct access * * This class defines functions to work with strides which can be used to access entries directly. This class * inherits DenseCoeffsBase which defines functions to access entries read-only using * \c operator() . * * \sa \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; using Base::rows; using Base::cols; using Base::size; using Base::derived; /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. * * \sa outerStride(), rowStride(), colStride() */ inline Index innerStride() const { return derived().innerStride(); } /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns * in a column-major matrix). * * \sa innerStride(), rowStride(), colStride() */ inline Index outerStride() const { return derived().outerStride(); } // FIXME shall we remove it ? inline Index stride() const { return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); } /** \returns the pointer increment between two consecutive rows. * * \sa innerStride(), outerStride(), colStride() */ inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); } /** \returns the pointer increment between two consecutive columns. * * \sa innerStride(), outerStride(), rowStride() */ inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); } }; /** \brief Base class providing direct read/write coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam DirectAccessors Constant indicating direct access * * This class defines functions to work with strides which can be used to access entries directly. This class * inherits DenseCoeffsBase which defines functions to access entries read/write using * \c operator(). * * \sa \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; using Base::rows; using Base::cols; using Base::size; using Base::derived; /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. * * \sa outerStride(), rowStride(), colStride() */ inline Index innerStride() const { return derived().innerStride(); } /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns * in a column-major matrix). * * \sa innerStride(), rowStride(), colStride() */ inline Index outerStride() const { return derived().outerStride(); } // FIXME shall we remove it ? inline Index stride() const { return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); } /** \returns the pointer increment between two consecutive rows. * * \sa innerStride(), outerStride(), colStride() */ inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); } /** \returns the pointer increment between two consecutive columns. * * \sa innerStride(), outerStride(), rowStride() */ inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); } }; namespace internal { template struct first_aligned_impl { inline static typename Derived::Index run(const Derived&) { return 0; } }; template struct first_aligned_impl { inline static typename Derived::Index run(const Derived& m) { return first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); } }; /** \internal \returns the index of the first element of the array that is well aligned for vectorization. * * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more * documentation. */ template inline static typename Derived::Index first_aligned(const Derived& m) { return first_aligned_impl ::run(m); } template::ret> struct inner_stride_at_compile_time { enum { ret = traits::InnerStrideAtCompileTime }; }; template struct inner_stride_at_compile_time { enum { ret = 0 }; }; template::ret> struct outer_stride_at_compile_time { enum { ret = traits::OuterStrideAtCompileTime }; }; template struct outer_stride_at_compile_time { enum { ret = 0 }; }; } // end namespace internal #endif // EIGEN_DENSECOEFFSBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/DenseStorage.h000066400000000000000000000324351172143270300222760ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2010 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MATRIXSTORAGE_H #define EIGEN_MATRIXSTORAGE_H #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN; #else #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN #endif namespace internal { struct constructor_without_unaligned_array_assert {}; /** \internal * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: * to 16 bytes boundary if the total size is a multiple of 16 bytes. */ template struct plain_array { T array[Size]; plain_array() {} plain_array(constructor_without_unaligned_array_assert) {} }; #ifdef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #endif template struct plain_array { EIGEN_USER_ALIGN16 T array[Size]; plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf) } plain_array(constructor_without_unaligned_array_assert) {} }; template struct plain_array { EIGEN_USER_ALIGN16 T array[1]; plain_array() {} plain_array(constructor_without_unaligned_array_assert) {} }; } // end namespace internal /** \internal * * \class DenseStorage * \ingroup Core_Module * * \brief Stores the data of a matrix * * This class stores the data of fixed-size, dynamic-size or mixed matrices * in a way as compact as possible. * * \sa Matrix */ template class DenseStorage; // purely fixed-size matrix template class DenseStorage { internal::plain_array m_data; public: inline explicit DenseStorage() {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } inline static DenseIndex rows(void) {return _Rows;} inline static DenseIndex cols(void) {return _Cols;} inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} inline void resize(DenseIndex,DenseIndex,DenseIndex) {} inline const T *data() const { return m_data.array; } inline T *data() { return m_data.array; } }; // null matrix template class DenseStorage { public: inline explicit DenseStorage() {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) {} inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} inline void swap(DenseStorage& ) {} inline static DenseIndex rows(void) {return _Rows;} inline static DenseIndex cols(void) {return _Cols;} inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} inline void resize(DenseIndex,DenseIndex,DenseIndex) {} inline const T *data() const { return 0; } inline T *data() { return 0; } }; // dynamic-size matrix with fixed-size storage template class DenseStorage { internal::plain_array m_data; DenseIndex m_rows; DenseIndex m_cols; public: inline explicit DenseStorage() : m_rows(0), m_cols(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} inline DenseStorage(DenseIndex, DenseIndex rows, DenseIndex cols) : m_rows(rows), m_cols(cols) {} inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } inline DenseIndex rows(void) const {return m_rows;} inline DenseIndex cols(void) const {return m_cols;} inline void conservativeResize(DenseIndex, DenseIndex rows, DenseIndex cols) { m_rows = rows; m_cols = cols; } inline void resize(DenseIndex, DenseIndex rows, DenseIndex cols) { m_rows = rows; m_cols = cols; } inline const T *data() const { return m_data.array; } inline T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed width template class DenseStorage { internal::plain_array m_data; DenseIndex m_rows; public: inline explicit DenseStorage() : m_rows(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} inline DenseStorage(DenseIndex, DenseIndex rows, DenseIndex) : m_rows(rows) {} inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } inline DenseIndex rows(void) const {return m_rows;} inline DenseIndex cols(void) const {return _Cols;} inline void conservativeResize(DenseIndex, DenseIndex rows, DenseIndex) { m_rows = rows; } inline void resize(DenseIndex, DenseIndex rows, DenseIndex) { m_rows = rows; } inline const T *data() const { return m_data.array; } inline T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed height template class DenseStorage { internal::plain_array m_data; DenseIndex m_cols; public: inline explicit DenseStorage() : m_cols(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} inline DenseStorage(DenseIndex, DenseIndex, DenseIndex cols) : m_cols(cols) {} inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } inline DenseIndex rows(void) const {return _Rows;} inline DenseIndex cols(void) const {return m_cols;} inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex cols) { m_cols = cols; } inline void resize(DenseIndex, DenseIndex, DenseIndex cols) { m_cols = cols; } inline const T *data() const { return m_data.array; } inline T *data() { return m_data.array; } }; // purely dynamic matrix. template class DenseStorage { T *m_data; DenseIndex m_rows; DenseIndex m_cols; public: inline explicit DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0), m_cols(0) {} inline DenseStorage(DenseIndex size, DenseIndex rows, DenseIndex cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } inline DenseIndex rows(void) const {return m_rows;} inline DenseIndex cols(void) const {return m_cols;} inline void conservativeResize(DenseIndex size, DenseIndex rows, DenseIndex cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); m_rows = rows; m_cols = cols; } void resize(DenseIndex size, DenseIndex rows, DenseIndex cols) { if(size != m_rows*m_cols) { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); if (size) m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } m_rows = rows; m_cols = cols; } inline const T *data() const { return m_data; } inline T *data() { return m_data; } }; // matrix with dynamic width and fixed height (so that matrix has dynamic size). template class DenseStorage { T *m_data; DenseIndex m_cols; public: inline explicit DenseStorage() : m_data(0), m_cols(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } inline static DenseIndex rows(void) {return _Rows;} inline DenseIndex cols(void) const {return m_cols;} inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); m_cols = cols; } EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex cols) { if(size != _Rows*m_cols) { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); if (size) m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } m_cols = cols; } inline const T *data() const { return m_data; } inline T *data() { return m_data; } }; // matrix with dynamic height and fixed width (so that matrix has dynamic size). template class DenseStorage { T *m_data; DenseIndex m_rows; public: inline explicit DenseStorage() : m_data(0), m_rows(0) {} inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} inline DenseStorage(DenseIndex size, DenseIndex rows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } inline DenseIndex rows(void) const {return m_rows;} inline static DenseIndex cols(void) {return _Cols;} inline void conservativeResize(DenseIndex size, DenseIndex rows, DenseIndex) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); m_rows = rows; } EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex rows, DenseIndex) { if(size != m_rows*_Cols) { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); if (size) m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } m_rows = rows; } inline const T *data() const { return m_data; } inline T *data() { return m_data; } }; #endif // EIGEN_MATRIX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Diagonal.h000066400000000000000000000214771172143270300214350ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DIAGONAL_H #define EIGEN_DIAGONAL_H /** \class Diagonal * \ingroup Core_Module * * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix * * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. * A positive value means a superdiagonal, a negative value means a subdiagonal. * You can also use Dynamic so the index can be set at runtime. * * The matrix is not required to be square. * * This class represents an expression of the main diagonal, or any sub/super diagonal * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the * time this is the only way it is used. * * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index) */ namespace internal { template struct traits > : traits { typedef typename nested::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { AbsDiagIndex = DiagIndex<0 ? -DiagIndex : DiagIndex, // only used if DiagIndex != Dynamic // FIXME these computations are broken in the case where the matrix is rectangular and DiagIndex!=0 RowsAtCompileTime = (int(DiagIndex) == Dynamic || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic : (EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime) - AbsDiagIndex), ColsAtCompileTime = 1, MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic : DiagIndex == Dynamic ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) : (EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) - AbsDiagIndex), MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, CoeffReadCost = _MatrixTypeNested::CoeffReadCost, MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 }; }; } template class Diagonal : public internal::dense_xpr_base< Diagonal >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) inline Diagonal(MatrixType& matrix, Index index = DiagIndex) : m_matrix(matrix), m_index(index) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) inline Index rows() const { return m_index.value()<0 ? std::min(m_matrix.cols(),m_matrix.rows()+m_index.value()) : std::min(m_matrix.rows(),m_matrix.cols()-m_index.value()); } inline Index cols() const { return 1; } inline Index innerStride() const { return m_matrix.outerStride() + 1; } inline Index outerStride() const { return 0; } inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); } inline const Scalar& coeffRef(Index row, Index) const { return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); } inline CoeffReturnType coeff(Index row, Index) const { return m_matrix.coeff(row+rowOffset(), row+colOffset()); } inline Scalar& coeffRef(Index index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.const_cast_derived().coeffRef(index+rowOffset(), index+colOffset()); } inline const Scalar& coeffRef(Index index) const { return m_matrix.const_cast_derived().coeffRef(index+rowOffset(), index+colOffset()); } inline CoeffReturnType coeff(Index index) const { return m_matrix.coeff(index+rowOffset(), index+colOffset()); } protected: const typename MatrixType::Nested m_matrix; const internal::variable_if_dynamic m_index; private: // some compilers may fail to optimize std::max etc in case of compile-time constants... EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } // triger a compile time error is someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; /** \returns an expression of the main diagonal of the matrix \c *this * * \c *this is not required to be square. * * Example: \include MatrixBase_diagonal.cpp * Output: \verbinclude MatrixBase_diagonal.out * * \sa class Diagonal */ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { return derived(); } /** This is the const version of diagonal(). */ template inline const typename MatrixBase::ConstDiagonalReturnType MatrixBase::diagonal() const { return ConstDiagonalReturnType(derived()); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this * * \c *this is not required to be square. * * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. * * Example: \include MatrixBase_diagonal_int.cpp * Output: \verbinclude MatrixBase_diagonal_int.out * * \sa MatrixBase::diagonal(), class Diagonal */ template inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal(Index index) { return typename DiagonalIndexReturnType::Type(derived(), index); } /** This is the const version of diagonal(Index). */ template inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal(Index index) const { return typename ConstDiagonalIndexReturnType::Type(derived(), index); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this * * \c *this is not required to be square. * * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. * * Example: \include MatrixBase_diagonal_template_int.cpp * Output: \verbinclude MatrixBase_diagonal_template_int.out * * \sa MatrixBase::diagonal(), class Diagonal */ template template inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { return derived(); } /** This is the const version of diagonal(). */ template template inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { return derived(); } #endif // EIGEN_DIAGONAL_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/DiagonalMatrix.h000066400000000000000000000264671172143270300226260ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DIAGONALMATRIX_H #define EIGEN_DIAGONALMATRIX_H #ifndef EIGEN_PARSED_BY_DOXYGEN template class DiagonalBase : public EigenBase { public: typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, Flags = 0 }; typedef Matrix DenseMatrixType; typedef DenseMatrixType DenseType; typedef DiagonalMatrix PlainObject; inline const Derived& derived() const { return *static_cast(this); } inline Derived& derived() { return *static_cast(this); } DenseMatrixType toDenseMatrix() const { return derived(); } template void evalTo(MatrixBase &other) const; template void addTo(MatrixBase &other) const { other.diagonal() += diagonal(); } template void subTo(MatrixBase &other) const { other.diagonal() -= diagonal(); } inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } inline DiagonalVectorType& diagonal() { return derived().diagonal(); } inline Index rows() const { return diagonal().size(); } inline Index cols() const { return diagonal().size(); } template const DiagonalProduct operator*(const MatrixBase &matrix) const; inline const DiagonalWrapper, const DiagonalVectorType> > inverse() const { return diagonal().cwiseInverse(); } #ifdef EIGEN2_SUPPORT template bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const { return diagonal().isApprox(other.diagonal(), precision); } template bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const { return toDenseMatrix().isApprox(other, precision); } #endif }; template template void DiagonalBase::evalTo(MatrixBase &other) const { other.setZero(); other.diagonal() = diagonal(); } #endif /** \class DiagonalMatrix * \ingroup Core_Module * * \brief Represents a diagonal matrix with its storage * * \param _Scalar the type of coefficients * \param SizeAtCompileTime the dimension of the matrix, or Dynamic * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults * to SizeAtCompileTime. Most of the time, you do not need to specify it. * * \sa class DiagonalWrapper */ namespace internal { template struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; typedef Dense StorageKind; typedef DenseIndex Index; enum { Flags = LvalueBit }; }; } template class DiagonalMatrix : public DiagonalBase > { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; #endif protected: DiagonalVectorType m_diagonal; public: /** const version of diagonal(). */ inline const DiagonalVectorType& diagonal() const { return m_diagonal; } /** \returns a reference to the stored vector of diagonal coefficients. */ inline DiagonalVectorType& diagonal() { return m_diagonal; } /** Default constructor without initialization */ inline DiagonalMatrix() {} /** Constructs a diagonal matrix with given dimension */ inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} /** 3D constructor. */ inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} /** Copy constructor. */ template inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */ inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {} #endif /** generic constructor from expression of the diagonal coefficients */ template explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) {} /** Copy operator. */ template DiagonalMatrix& operator=(const DiagonalBase& other) { m_diagonal = other.diagonal(); return *this; } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ DiagonalMatrix& operator=(const DiagonalMatrix& other) { m_diagonal = other.diagonal(); return *this; } #endif /** Resizes to given size. */ inline void resize(Index size) { m_diagonal.resize(size); } /** Sets all coefficients to zero. */ inline void setZero() { m_diagonal.setZero(); } /** Resizes and sets all coefficients to zero. */ inline void setZero(Index size) { m_diagonal.setZero(size); } /** Sets this matrix to be the identity matrix of the current size. */ inline void setIdentity() { m_diagonal.setOnes(); } /** Sets this matrix to be the identity matrix of the given size. */ inline void setIdentity(Index size) { m_diagonal.setOnes(size); } }; /** \class DiagonalWrapper * \ingroup Core_Module * * \brief Expression of a diagonal matrix * * \param _DiagonalVectorType the type of the vector of diagonal coefficients * * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients, * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal() * and most of the time this is the only way that it is used. * * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal() */ namespace internal { template struct traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::Index Index; typedef typename DiagonalVectorType::StorageKind StorageKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, Flags = traits::Flags & LvalueBit }; }; } template class DiagonalWrapper : public DiagonalBase >, internal::no_assignment_operator { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef _DiagonalVectorType DiagonalVectorType; typedef DiagonalWrapper Nested; #endif /** Constructor from expression of diagonal coefficients to wrap. */ inline DiagonalWrapper(const DiagonalVectorType& diagonal) : m_diagonal(diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: const typename DiagonalVectorType::Nested m_diagonal; }; /** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients * * \only_for_vectors * * Example: \include MatrixBase_asDiagonal.cpp * Output: \verbinclude MatrixBase_asDiagonal.out * * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal() **/ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { return derived(); } /** \returns true if *this is approximately equal to a diagonal matrix, * within the precision given by \a prec. * * Example: \include MatrixBase_isDiagonal.cpp * Output: \verbinclude MatrixBase_isDiagonal.out * * \sa asDiagonal() */ template bool MatrixBase::isDiagonal(RealScalar prec) const { if(cols() != rows()) return false; RealScalar maxAbsOnDiagonal = static_cast(-1); for(Index j = 0; j < cols(); ++j) { RealScalar absOnDiagonal = internal::abs(coeff(j,j)); if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; } for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < j; ++i) { if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false; if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false; } return true; } #endif // EIGEN_DIAGONALMATRIX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/DiagonalProduct.h000066400000000000000000000137461172143270300227760ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DIAGONALPRODUCT_H #define EIGEN_DIAGONALPRODUCT_H namespace internal { template struct traits > : traits { typedef typename scalar_product_traits::ReturnType Scalar; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, _PacketOnDiag = !((int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) ||(int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), _SameTypes = is_same::value, // FIXME currently we need same types, but in the future the next rule should be the one //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::Flags)&PacketAccessBit))), _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && ((!_PacketOnDiag) || (bool(int(DiagonalType::Flags)&PacketAccessBit))), Flags = (HereditaryBits & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0), CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost }; }; } template class DiagonalProduct : internal::no_assignment_operator, public MatrixBase > { public: typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) : m_matrix(matrix), m_diagonal(diagonal) { eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); } inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } const Scalar coeff(Index row, Index col) const { return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); } template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { enum { StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor }; const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); } protected: template EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const { return internal::pmul(m_matrix.template packet(row, col), internal::pset1(m_diagonal.diagonal().coeff(id))); } template EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const { enum { InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, DiagonalVectorPacketLoadMode = (LoadMode == Aligned && ((InnerSize%16) == 0)) ? Aligned : Unaligned }; return internal::pmul(m_matrix.template packet(row, col), m_diagonal.diagonal().template packet(id)); } const typename MatrixType::Nested m_matrix; const typename DiagonalType::Nested m_diagonal; }; /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. */ template template inline const DiagonalProduct MatrixBase::operator*(const DiagonalBase &diagonal) const { return DiagonalProduct(derived(), diagonal.derived()); } /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. */ template template inline const DiagonalProduct DiagonalBase::operator*(const MatrixBase &matrix) const { return DiagonalProduct(matrix.derived(), derived()); } #endif // EIGEN_DIAGONALPRODUCT_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Dot.h000066400000000000000000000230471172143270300204400ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008, 2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DOT_H #define EIGEN_DOT_H namespace internal { // helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot // with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE // looking at the static assertions. Thus this is a trick to get better compile errors. template struct dot_nocheck { typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); } }; template struct dot_nocheck { typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); } }; } // end namespace internal /** \returns the dot product of *this with other. * * \only_for_vectors * * \note If the scalar type is complex numbers, then this function returns the hermitian * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the * second variable. * * \sa squaredNorm(), norm() */ template template typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType MatrixBase::dot(const MatrixBase& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) typedef internal::scalar_conj_product_op func; EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); eigen_assert(size() == other.size()); return internal::dot_nocheck::run(*this, other); } #ifdef EIGEN2_SUPPORT /** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable * (conjugating the second variable). Of course this only makes a difference in the complex case. * * This method is only available in EIGEN2_SUPPORT mode. * * \only_for_vectors * * \sa dot() */ template template typename internal::traits::Scalar MatrixBase::eigen2_dot(const MatrixBase& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) eigen_assert(size() == other.size()); return internal::dot_nocheck::run(other,*this); } #endif //---------- implementation of L2 norm and related functions ---------- /** \returns the squared \em l2 norm of *this, i.e., for vectors, the dot product of *this with itself. * * \sa dot(), norm() */ template EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const { return internal::real((*this).cwiseAbs2().sum()); } /** \returns the \em l2 norm of *this, i.e., for vectors, the square root of the dot product of *this with itself. * * \sa dot(), squaredNorm() */ template inline typename NumTraits::Scalar>::Real MatrixBase::norm() const { return internal::sqrt(squaredNorm()); } /** \returns an expression of the quotient of *this by its own norm. * * \only_for_vectors * * \sa norm(), normalize() */ template inline const typename MatrixBase::PlainObject MatrixBase::normalized() const { typedef typename internal::nested::type Nested; typedef typename internal::remove_reference::type _Nested; _Nested n(derived()); return n / n.norm(); } /** Normalizes the vector, i.e. divides it by its own norm. * * \only_for_vectors * * \sa norm(), normalized() */ template inline void MatrixBase::normalize() { *this /= norm(); } //---------- implementation of other norms ---------- namespace internal { template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; inline static RealScalar run(const MatrixBase& m) { return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } }; template struct lpNorm_selector { inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); } }; template struct lpNorm_selector { inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); } }; template struct lpNorm_selector { inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().maxCoeff(); } }; } // end namespace internal /** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ * norm, that is the maximum of the absolute values of the coefficients of *this. * * \sa norm() */ template template inline typename NumTraits::Scalar>::Real MatrixBase::lpNorm() const { return internal::lpNorm_selector::run(*this); } //---------- implementation of isOrthogonal / isUnitary ---------- /** \returns true if *this is approximately orthogonal to \a other, * within the precision given by \a prec. * * Example: \include MatrixBase_isOrthogonal.cpp * Output: \verbinclude MatrixBase_isOrthogonal.out */ template template bool MatrixBase::isOrthogonal (const MatrixBase& other, RealScalar prec) const { typename internal::nested::type nested(derived()); typename internal::nested::type otherNested(other.derived()); return internal::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } /** \returns true if *this is approximately an unitary matrix, * within the precision given by \a prec. In the case where the \a Scalar * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name. * * \note This can be used to check whether a family of vectors forms an orthonormal basis. * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an * orthonormal basis. * * Example: \include MatrixBase_isUnitary.cpp * Output: \verbinclude MatrixBase_isUnitary.out */ template bool MatrixBase::isUnitary(RealScalar prec) const { typename Derived::Nested nested(derived()); for(Index i = 0; i < cols(); ++i) { if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) return false; for(Index j = 0; j < i; ++j) if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) return false; } return true; } #endif // EIGEN_DOT_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/EigenBase.h000066400000000000000000000143531172143270300215340ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_EIGENBASE_H #define EIGEN_EIGENBASE_H /** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * * In other words, an EigenBase object is an object that can be copied into a MatrixBase. * * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. * * \sa \ref TopicClassHierarchy */ template struct EigenBase { // typedef typename internal::plain_matrix_type::type PlainObject; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; /** \returns a reference to the derived object */ Derived& derived() { return *static_cast(this); } /** \returns a const reference to the derived object */ const Derived& derived() const { return *static_cast(this); } inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } inline const Derived& const_derived() const { return *static_cast(this); } /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ inline Index rows() const { return derived().rows(); } /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ inline Index cols() const { return derived().cols(); } /** \returns the number of coefficients, which is rows()*cols(). * \sa rows(), cols(), SizeAtCompileTime. */ inline Index size() const { return rows() * cols(); } /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ template inline void evalTo(Dest& dst) const { derived().evalTo(dst); } /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ template inline void addTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. typename Dest::PlainObject res(rows(),cols()); evalTo(res); dst += res; } /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ template inline void subTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. typename Dest::PlainObject res(rows(),cols()); evalTo(res); dst -= res; } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ template inline void applyThisOnTheRight(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. dst = dst * this->derived(); } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ template inline void applyThisOnTheLeft(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. dst = this->derived() * dst; } }; /*************************************************************************** * Implementation of matrix base methods ***************************************************************************/ /** \brief Copies the generic expression \a other into *this. * * \details The expression must provide a (templated) evalTo(Derived& dst) const * function which does the actual job. In practice, this allows any user to write * its own special matrix without having to modify MatrixBase * * \returns a reference to *this. */ template template Derived& DenseBase::operator=(const EigenBase &other) { other.derived().evalTo(derived()); return derived(); } template template Derived& DenseBase::operator+=(const EigenBase &other) { other.derived().addTo(derived()); return derived(); } template template Derived& DenseBase::operator-=(const EigenBase &other) { other.derived().subTo(derived()); return derived(); } /** replaces \c *this by \c *this * \a other. * * \returns a reference to \c *this */ template template inline Derived& MatrixBase::operator*=(const EigenBase &other) { other.derived().applyThisOnTheRight(derived()); return derived(); } /** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=() */ template template inline void MatrixBase::applyOnTheRight(const EigenBase &other) { other.derived().applyThisOnTheRight(derived()); } /** replaces \c *this by \c *this * \a other. */ template template inline void MatrixBase::applyOnTheLeft(const EigenBase &other) { other.derived().applyThisOnTheLeft(derived()); } #endif // EIGEN_EIGENBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Flagged.h000066400000000000000000000114651172143270300212440ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_FLAGGED_H #define EIGEN_FLAGGED_H /** \class Flagged * \ingroup Core_Module * * \brief Expression with modified flags * * \param ExpressionType the type of the object of which we are modifying the flags * \param Added the flags added to the expression * \param Removed the flags removed from the expression (has priority over Added). * * This class represents an expression whose flags have been modified. * It is the return type of MatrixBase::flagged() * and most of the time this is the only way it is used. * * \sa MatrixBase::flagged() */ namespace internal { template struct traits > : traits { enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; }; } template class Flagged : public MatrixBase > { public: typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) typedef typename internal::conditional::ret, ExpressionType, const ExpressionType&>::type ExpressionTypeNested; typedef typename ExpressionType::InnerIterator InnerIterator; inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } inline Index outerStride() const { return m_matrix.outerStride(); } inline Index innerStride() const { return m_matrix.innerStride(); } inline CoeffReturnType coeff(Index row, Index col) const { return m_matrix.coeff(row, col); } inline CoeffReturnType coeff(Index index) const { return m_matrix.coeff(index); } inline const Scalar& coeffRef(Index row, Index col) const { return m_matrix.const_cast_derived().coeffRef(row, col); } inline const Scalar& coeffRef(Index index) const { return m_matrix.const_cast_derived().coeffRef(index); } inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(row, col); } inline Scalar& coeffRef(Index index) { return m_matrix.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_matrix.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_matrix.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_matrix.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_matrix.const_cast_derived().template writePacket(index, x); } const ExpressionType& _expression() const { return m_matrix; } template typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; template void solveTriangularInPlace(const MatrixBase& other) const; protected: ExpressionTypeNested m_matrix; }; /** \returns an expression of *this with added and removed flags * * This is mostly for internal use. * * \sa class Flagged */ template template inline const Flagged DenseBase::flagged() const { return derived(); } #endif // EIGEN_FLAGGED_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/ForceAlignedAccess.h000066400000000000000000000120731172143270300233530ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_FORCEALIGNEDACCESS_H #define EIGEN_FORCEALIGNEDACCESS_H /** \class ForceAlignedAccess * \ingroup Core_Module * * \brief Enforce aligned packet loads and stores regardless of what is requested * * \param ExpressionType the type of the object of which we are forcing aligned packet access * * This class is the return type of MatrixBase::forceAlignedAccess() * and most of the time this is the only way it is used. * * \sa MatrixBase::forceAlignedAccess() */ namespace internal { template struct traits > : public traits {}; } template class ForceAlignedAccess : public internal::dense_xpr_base< ForceAlignedAccess >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } inline Index outerStride() const { return m_expression.outerStride(); } inline Index innerStride() const { return m_expression.innerStride(); } inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; private: ForceAlignedAccess& operator=(const ForceAlignedAccess&); }; /** \returns an expression of *this with forced aligned access * \sa forceAlignedAccessIf(),class ForceAlignedAccess */ template inline const ForceAlignedAccess MatrixBase::forceAlignedAccess() const { return ForceAlignedAccess(derived()); } /** \returns an expression of *this with forced aligned access * \sa forceAlignedAccessIf(), class ForceAlignedAccess */ template inline ForceAlignedAccess MatrixBase::forceAlignedAccess() { return ForceAlignedAccess(derived()); } /** \returns an expression of *this with forced aligned access if \a Enable is true. * \sa forceAlignedAccess(), class ForceAlignedAccess */ template template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { return derived(); } /** \returns an expression of *this with forced aligned access if \a Enable is true. * \sa forceAlignedAccess(), class ForceAlignedAccess */ template template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { return derived(); } #endif // EIGEN_FORCEALIGNEDACCESS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Functors.h000066400000000000000000001062231172143270300215130ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_FUNCTORS_H #define EIGEN_FUNCTORS_H namespace internal { // associative functors: /** \internal * \brief Template functor to compute the sum of two scalars * * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() */ template struct scalar_sum_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::padd(a,b); } template EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const { return internal::predux(a); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; /** \internal * \brief Template functor to compute the product of two scalars * * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() */ template struct scalar_product_op { enum { // TODO vectorize mixed product Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul }; typedef typename scalar_product_traits::ReturnType result_type; EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmul(a,b); } template EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const { return internal::predux_mul(a); } }; template struct functor_traits > { enum { Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! PacketAccess = scalar_product_op::Vectorizable }; }; /** \internal * \brief Template functor to compute the conjugate product of two scalars * * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) */ template struct scalar_conj_product_op { enum { Conj = NumTraits::IsComplex }; typedef typename scalar_product_traits::ReturnType result_type; EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return conj_helper().pmul(a,b); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return conj_helper().pmul(a,b); } }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = internal::is_same::value && packet_traits::HasMul }; }; /** \internal * \brief Template functor to compute the min of two scalars * * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() */ template struct scalar_min_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return std::min(a, b); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmin(a,b); } template EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const { return internal::predux_min(a); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasMin }; }; /** \internal * \brief Template functor to compute the max of two scalars * * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() */ template struct scalar_max_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return std::max(a, b); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmax(a,b); } template EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const { return internal::predux_max(a); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasMax }; }; /** \internal * \brief Template functor to compute the hypot of two scalars * * \sa MatrixBase::stableNorm(), class Redux */ template struct scalar_hypot_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) // typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const { Scalar p = std::max(_x, _y); Scalar q = std::min(_x, _y); Scalar qp = q/p; return p * sqrt(Scalar(1) + qp*qp); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; }; // other binary functors: /** \internal * \brief Template functor to compute the difference of two scalars * * \sa class CwiseBinaryOp, MatrixBase::operator- */ template struct scalar_difference_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::psub(a,b); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasSub }; }; /** \internal * \brief Template functor to compute the quotient of two scalars * * \sa class CwiseBinaryOp, Cwise::operator/() */ template struct scalar_quotient_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a / b; } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pdiv(a,b); } }; template struct functor_traits > { enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; // unary functors: /** \internal * \brief Template functor to compute the opposite of a scalar * * \sa class CwiseUnaryOp, MatrixBase::operator- */ template struct scalar_opposite_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pnegate(a); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasNegate }; }; /** \internal * \brief Template functor to compute the absolute value of a scalar * * \sa class CwiseUnaryOp, Cwise::abs */ template struct scalar_abs_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return abs(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pabs(a); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAbs }; }; /** \internal * \brief Template functor to compute the squared absolute value of a scalar * * \sa class CwiseUnaryOp, Cwise::abs2 */ template struct scalar_abs2_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return abs2(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pmul(a,a); } }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; /** \internal * \brief Template functor to compute the conjugate of a complex value * * \sa class CwiseUnaryOp, MatrixBase::conjugate() */ template struct scalar_conjugate_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return conj(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } }; template struct functor_traits > { enum { Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, PacketAccess = packet_traits::HasConj }; }; /** \internal * \brief Template functor to cast a scalar to another type * * \sa class CwiseUnaryOp, MatrixBase::cast() */ template struct scalar_cast_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) typedef NewType result_type; EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } }; template struct functor_traits > { enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; /** \internal * \brief Template functor to extract the real part of a complex * * \sa class CwiseUnaryOp, MatrixBase::real() */ template struct scalar_real_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return real(a); } }; template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; /** \internal * \brief Template functor to extract the imaginary part of a complex * * \sa class CwiseUnaryOp, MatrixBase::imag() */ template struct scalar_imag_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return imag(a); } }; template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; /** \internal * \brief Template functor to extract the real part of a complex as a reference * * \sa class CwiseUnaryOp, MatrixBase::real() */ template struct scalar_real_ref_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return real_ref(*const_cast(&a)); } }; template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; /** \internal * \brief Template functor to extract the imaginary part of a complex as a reference * * \sa class CwiseUnaryOp, MatrixBase::imag() */ template struct scalar_imag_ref_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) typedef typename NumTraits::Real result_type; EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return imag_ref(*const_cast(&a)); } }; template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; /** \internal * * \brief Template functor to compute the exponential of a scalar * * \sa class CwiseUnaryOp, Cwise::exp() */ template struct scalar_exp_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) inline const Scalar operator() (const Scalar& a) const { return exp(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; /** \internal * * \brief Template functor to compute the logarithm of a scalar * * \sa class CwiseUnaryOp, Cwise::log() */ template struct scalar_log_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) inline const Scalar operator() (const Scalar& a) const { return log(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::plog(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; /** \internal * \brief Template functor to multiply a scalar by a fixed other one * * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ */ /* NOTE why doing the pset1() in packetOp *is* an optimization ? * indeed it seems better to declare m_other as a Packet and do the pset1() once * in the constructor. However, in practice: * - GCC does not like m_other as a Packet and generate a load every time it needs it * - on the other hand GCC is able to moves the pset1() away the loop :) * - simpler code ;) * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) */ template struct scalar_multiple_op { typedef typename packet_traits::type Packet; // FIXME default copy constructors seems bugged with std::complex<> EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pmul(a, pset1(m_other)); } typename add_const_on_value_type::Nested>::type m_other; }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; template struct scalar_multiple2_op { typedef typename scalar_product_traits::ReturnType result_type; EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } typename add_const_on_value_type::Nested>::type m_other; }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; template struct scalar_quotient1_impl { typedef typename packet_traits::type Packet; // FIXME default copy constructors seems bugged with std::complex<> EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(static_cast(1) / other) {} EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pmul(a, pset1(m_other)); } const Scalar m_other; }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; template struct scalar_quotient1_impl { // FIXME default copy constructors seems bugged with std::complex<> EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(other) {} EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } typename add_const_on_value_type::Nested>::type m_other; }; template struct functor_traits > { enum { Cost = 2 * NumTraits::MulCost, PacketAccess = false }; }; /** \internal * \brief Template functor to divide a scalar by a fixed other one * * This functor is used to implement the quotient of a matrix by * a scalar where the scalar type is not necessarily a floating point type. * * \sa class CwiseUnaryOp, MatrixBase::operator/ */ template struct scalar_quotient1_op : scalar_quotient1_impl::IsInteger > { EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : scalar_quotient1_impl::IsInteger >(other) {} }; template struct functor_traits > : functor_traits::IsInteger> > {}; // nullary functors template struct scalar_constant_op { typedef typename packet_traits::type Packet; EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } template EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } template EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } const Scalar m_other; }; template struct functor_traits > // FIXME replace this packet test by a safe one { enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; template struct scalar_identity_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) template EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; template struct linspaced_op_impl; // linear access for packet ops: // 1) initialization // base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) // 2) each step // base += [size*step, ..., size*step] template struct linspaced_op_impl { typedef typename packet_traits::type Packet; linspaced_op_impl(Scalar low, Scalar step) : m_low(low), m_step(step), m_packetStep(pset1(packet_traits::size*step)), m_base(padd(pset1(low),pmul(pset1(step),plset(-packet_traits::size)))) {} template EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } template EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } const Scalar m_low; const Scalar m_step; const Packet m_packetStep; mutable Packet m_base; }; // random access for packet ops: // 1) each step // [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) template struct linspaced_op_impl { typedef typename packet_traits::type Packet; linspaced_op_impl(Scalar low, Scalar step) : m_low(low), m_step(step), m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} template EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } template EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(i),m_interPacket))); } const Scalar m_low; const Scalar m_step; const Packet m_lowPacket; const Packet m_stepPacket; const Packet m_interPacket; }; // ----- Linspace functor ---------------------------------------------------------------- // Forward declaration (we default to random access which does not really give // us a speed gain when using packet access but it allows to use the functor in // nested expressions). template struct linspaced_op; template struct functor_traits< linspaced_op > { enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; template struct linspaced_op { typedef typename packet_traits::type Packet; linspaced_op(Scalar low, Scalar high, int num_steps) : impl(low, (high-low)/(num_steps-1)) {} template EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since // there row==0 and col is used for the actual iteration. template EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { eigen_assert(col==0 || row==0); return impl(col + row); } template EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since // there row==0 and col is used for the actual iteration. template EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const { eigen_assert(col==0 || row==0); return impl(col + row); } // This proxy object handles the actual required temporaries, the different // implementations (random vs. sequential access) as well as the // correct piping to size 2/4 packet operations. const linspaced_op_impl impl; }; // all functors allow linear access, except scalar_identity_op. So we fix here a quick meta // to indicate whether a functor allows linear access, just always answering 'yes' except for // scalar_identity_op. // FIXME move this to functor_traits adding a functor_default template struct functor_has_linear_access { enum { ret = 1 }; }; template struct functor_has_linear_access > { enum { ret = 0 }; }; // in CwiseBinaryOp, we require the Lhs and Rhs to have the same scalar type, except for multiplication // where we only require them to have the same _real_ scalar type so one may multiply, say, float by complex. // FIXME move this to functor_traits adding a functor_default template struct functor_allows_mixing_real_and_complex { enum { ret = 0 }; }; template struct functor_allows_mixing_real_and_complex > { enum { ret = 1 }; }; template struct functor_allows_mixing_real_and_complex > { enum { ret = 1 }; }; /** \internal * \brief Template functor to add a scalar to a fixed other one * \sa class CwiseUnaryOp, Array::operator+ */ /* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ template struct scalar_add_op { typedef typename packet_traits::type Packet; // FIXME default copy constructors seems bugged with std::complex<> inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } inline scalar_add_op(const Scalar& other) : m_other(other) { } inline Scalar operator() (const Scalar& a) const { return a + m_other; } inline const Packet packetOp(const Packet& a) const { return internal::padd(a, pset1(m_other)); } const Scalar m_other; }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; /** \internal * \brief Template functor to compute the square root of a scalar * \sa class CwiseUnaryOp, Cwise::sqrt() */ template struct scalar_sqrt_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) inline const Scalar operator() (const Scalar& a) const { return sqrt(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasSqrt }; }; /** \internal * \brief Template functor to compute the cosine of a scalar * \sa class CwiseUnaryOp, ArrayBase::cos() */ template struct scalar_cos_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) inline Scalar operator() (const Scalar& a) const { return cos(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasCos }; }; /** \internal * \brief Template functor to compute the sine of a scalar * \sa class CwiseUnaryOp, ArrayBase::sin() */ template struct scalar_sin_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) inline const Scalar operator() (const Scalar& a) const { return sin(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::psin(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasSin }; }; /** \internal * \brief Template functor to compute the tan of a scalar * \sa class CwiseUnaryOp, ArrayBase::tan() */ template struct scalar_tan_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) inline const Scalar operator() (const Scalar& a) const { return tan(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasTan }; }; /** \internal * \brief Template functor to compute the arc cosine of a scalar * \sa class CwiseUnaryOp, ArrayBase::acos() */ template struct scalar_acos_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) inline const Scalar operator() (const Scalar& a) const { return acos(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasACos }; }; /** \internal * \brief Template functor to compute the arc sine of a scalar * \sa class CwiseUnaryOp, ArrayBase::asin() */ template struct scalar_asin_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) inline const Scalar operator() (const Scalar& a) const { return acos(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasASin }; }; /** \internal * \brief Template functor to raise a scalar to a power * \sa class CwiseUnaryOp, Cwise::pow */ template struct scalar_pow_op { // FIXME default copy constructors seems bugged with std::complex<> inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} inline Scalar operator() (const Scalar& a) const { return internal::pow(a, m_exponent); } const Scalar m_exponent; }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; /** \internal * \brief Template functor to compute the inverse of a scalar * \sa class CwiseUnaryOp, Cwise::inverse() */ template struct scalar_inverse_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } template inline const Packet packetOp(const Packet& a) const { return internal::pdiv(pset1(Scalar(1)),a); } }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; /** \internal * \brief Template functor to compute the square of a scalar * \sa class CwiseUnaryOp, Cwise::square() */ template struct scalar_square_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) inline Scalar operator() (const Scalar& a) const { return a*a; } template inline const Packet packetOp(const Packet& a) const { return internal::pmul(a,a); } }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; /** \internal * \brief Template functor to compute the cube of a scalar * \sa class CwiseUnaryOp, Cwise::cube() */ template struct scalar_cube_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) inline Scalar operator() (const Scalar& a) const { return a*a*a; } template inline const Packet packetOp(const Packet& a) const { return internal::pmul(a,pmul(a,a)); } }; template struct functor_traits > { enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; // default functor traits for STL functors: template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = functor_traits::Cost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = functor_traits::Cost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; #ifdef EIGEN_STDEXT_SUPPORT template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = 0, PacketAccess = false }; }; template struct functor_traits > > { enum { Cost = 0, PacketAccess = false }; }; template struct functor_traits > > { enum { Cost = 0, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; template struct functor_traits > { enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; #endif // EIGEN_STDEXT_SUPPORT // allow to add new functors and specializations of functor_traits from outside Eigen. // this macro is really needed because functor_traits must be specialized after it is declared but before it is used... #ifdef EIGEN_FUNCTORS_PLUGIN #include EIGEN_FUNCTORS_PLUGIN #endif } // end namespace internal #endif // EIGEN_FUNCTORS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Fuzzy.h000066400000000000000000000141161172143270300210360ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_FUZZY_H #define EIGEN_FUZZY_H namespace internal { template::IsInteger> struct isApprox_selector { static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar prec) { const typename internal::nested::type nested(x); const typename internal::nested::type otherNested(y); return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * std::min(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; template struct isApprox_selector { static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar) { return x.matrix() == y.matrix(); } }; template::IsInteger> struct isMuchSmallerThan_object_selector { static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar prec) { return x.cwiseAbs2().sum() <= abs2(prec) * y.cwiseAbs2().sum(); } }; template struct isMuchSmallerThan_object_selector { static bool run(const Derived& x, const OtherDerived&, typename Derived::RealScalar) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); } }; template::IsInteger> struct isMuchSmallerThan_scalar_selector { static bool run(const Derived& x, const typename Derived::RealScalar& y, typename Derived::RealScalar prec) { return x.cwiseAbs2().sum() <= abs2(prec * y); } }; template struct isMuchSmallerThan_scalar_selector { static bool run(const Derived& x, const typename Derived::RealScalar&, typename Derived::RealScalar) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); } }; } // end namespace internal /** \returns \c true if \c *this is approximately equal to \a other, within the precision * determined by \a prec. * * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$ * are considered to be approximately equal within precision \f$ p \f$ if * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f] * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm * L2 norm). * * \note Because of the multiplicativeness of this comparison, one can't use this function * to check whether \c *this is approximately equal to the zero matrix or vector. * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const * RealScalar&, RealScalar) instead. * * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const */ template template bool DenseBase::isApprox( const DenseBase& other, RealScalar prec ) const { return internal::isApprox_selector::run(derived(), other.derived(), prec); } /** \returns \c true if the norm of \c *this is much smaller than \a other, * within the precision determined by \a prec. * * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f] * * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason, * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm * of a reference matrix of same dimensions. * * \sa isApprox(), isMuchSmallerThan(const DenseBase&, RealScalar) const */ template bool DenseBase::isMuchSmallerThan( const typename NumTraits::Real& other, RealScalar prec ) const { return internal::isMuchSmallerThan_scalar_selector::run(derived(), other, prec); } /** \returns \c true if the norm of \c *this is much smaller than the norm of \a other, * within the precision determined by \a prec. * * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f] * For matrices, the comparison is done using the Hilbert-Schmidt norm. * * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const */ template template bool DenseBase::isMuchSmallerThan( const DenseBase& other, RealScalar prec ) const { return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); } #endif // EIGEN_FUZZY_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/GenericPacketMath.h000066400000000000000000000273301172143270300232270ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_GENERIC_PACKET_MATH_H #define EIGEN_GENERIC_PACKET_MATH_H namespace internal { /** \internal * \file GenericPacketMath.h * * Default implementation for types not supported by the vectorization. * In practice these functions are provided to make easier the writing * of generic vectorized code. */ #ifndef EIGEN_DEBUG_ALIGNED_LOAD #define EIGEN_DEBUG_ALIGNED_LOAD #endif #ifndef EIGEN_DEBUG_UNALIGNED_LOAD #define EIGEN_DEBUG_UNALIGNED_LOAD #endif #ifndef EIGEN_DEBUG_ALIGNED_STORE #define EIGEN_DEBUG_ALIGNED_STORE #endif #ifndef EIGEN_DEBUG_UNALIGNED_STORE #define EIGEN_DEBUG_UNALIGNED_STORE #endif struct default_packet_traits { enum { HasAdd = 1, HasSub = 1, HasMul = 1, HasNegate = 1, HasAbs = 1, HasAbs2 = 1, HasMin = 1, HasMax = 1, HasConj = 1, HasSetLinear = 1, HasDiv = 0, HasSqrt = 0, HasExp = 0, HasLog = 0, HasPow = 0, HasSin = 0, HasCos = 0, HasTan = 0, HasASin = 0, HasACos = 0, HasATan = 0 }; }; template struct packet_traits : default_packet_traits { typedef T type; enum { Vectorizable = 0, size = 1, AlignedOnScalar = 0 }; enum { HasAdd = 0, HasSub = 0, HasMul = 0, HasNegate = 0, HasAbs = 0, HasAbs2 = 0, HasMin = 0, HasMax = 0, HasConj = 0, HasSetLinear = 0 }; }; /** \internal \returns a + b (coeff-wise) */ template inline Packet padd(const Packet& a, const Packet& b) { return a+b; } /** \internal \returns a - b (coeff-wise) */ template inline Packet psub(const Packet& a, const Packet& b) { return a-b; } /** \internal \returns -a (coeff-wise) */ template inline Packet pnegate(const Packet& a) { return -a; } /** \internal \returns conj(a) (coeff-wise) */ template inline Packet pconj(const Packet& a) { return conj(a); } /** \internal \returns a * b (coeff-wise) */ template inline Packet pmul(const Packet& a, const Packet& b) { return a*b; } /** \internal \returns a / b (coeff-wise) */ template inline Packet pdiv(const Packet& a, const Packet& b) { return a/b; } /** \internal \returns the min of \a a and \a b (coeff-wise) */ template inline Packet pmin(const Packet& a, const Packet& b) { return std::min(a, b); } /** \internal \returns the max of \a a and \a b (coeff-wise) */ template inline Packet pmax(const Packet& a, const Packet& b) { return std::max(a, b); } /** \internal \returns the absolute value of \a a */ template inline Packet pabs(const Packet& a) { return abs(a); } /** \internal \returns the bitwise and of \a a and \a b */ template inline Packet pand(const Packet& a, const Packet& b) { return a & b; } /** \internal \returns the bitwise or of \a a and \a b */ template inline Packet por(const Packet& a, const Packet& b) { return a | b; } /** \internal \returns the bitwise xor of \a a and \a b */ template inline Packet pxor(const Packet& a, const Packet& b) { return a ^ b; } /** \internal \returns the bitwise andnot of \a a and \a b */ template inline Packet pandnot(const Packet& a, const Packet& b) { return a & (!b); } /** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ template inline Packet pload(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet version of \a *from, (un-aligned load) */ template inline Packet ploadu(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet with elements of \a *from duplicated, e.g.: (from[0],from[0],from[1],from[1]) */ template inline Packet ploaddup(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ template inline Packet pset1(const typename unpacket_traits::type& a) { return a; } /** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ template inline typename packet_traits::type plset(const Scalar& a) { return a; } /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ template inline void pstore(Scalar* to, const Packet& from) { (*to) = from; } /** \internal copy the packet \a from to \a *to, (un-aligned store) */ template inline void pstoreu(Scalar* to, const Packet& from) { (*to) = from; } /** \internal tries to do cache prefetching of \a addr */ template inline void prefetch(const Scalar* addr) { #if !defined(_MSC_VER) __builtin_prefetch(addr); #endif } /** \internal \returns the first element of a packet */ template inline typename unpacket_traits::type pfirst(const Packet& a) { return a; } /** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ template inline Packet preduxp(const Packet* vecs) { return vecs[0]; } /** \internal \returns the sum of the elements of \a a*/ template inline typename unpacket_traits::type predux(const Packet& a) { return a; } /** \internal \returns the product of the elements of \a a*/ template inline typename unpacket_traits::type predux_mul(const Packet& a) { return a; } /** \internal \returns the min of the elements of \a a*/ template inline typename unpacket_traits::type predux_min(const Packet& a) { return a; } /** \internal \returns the max of the elements of \a a*/ template inline typename unpacket_traits::type predux_max(const Packet& a) { return a; } /** \internal \returns the reversed elements of \a a*/ template inline Packet preverse(const Packet& a) { return a; } /** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ template inline Packet pcplxflip(const Packet& a) { return Packet(imag(a),real(a)); } /************************** * Special math functions ***************************/ /** \internal \returns the sine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psin(const Packet& a) { return sin(a); } /** \internal \returns the cosine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pcos(const Packet& a) { return cos(a); } /** \internal \returns the tan of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet ptan(const Packet& a) { return tan(a); } /** \internal \returns the arc sine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pasin(const Packet& a) { return asin(a); } /** \internal \returns the arc cosine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pacos(const Packet& a) { return acos(a); } /** \internal \returns the exp of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { return exp(a); } /** \internal \returns the log of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet& a) { return log(a); } /** \internal \returns the square-root of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psqrt(const Packet& a) { return sqrt(a); } /*************************************************************************** * The following functions might not have to be overwritten for vectorized types ***************************************************************************/ /** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ // NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) template inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) { pstore(to, pset1(a)); } /** \internal \returns a * b + c (coeff-wise) */ template inline Packet pmadd(const Packet& a, const Packet& b, const Packet& c) { return padd(pmul(a, b),c); } /** \internal \returns a packet version of \a *from. * \If LoadMode equals Aligned, \a from must be 16 bytes aligned */ template inline Packet ploadt(const typename unpacket_traits::type* from) { if(LoadMode == Aligned) return pload(from); else return ploadu(from); } /** \internal copy the packet \a from to \a *to. * If StoreMode equals Aligned, \a to must be 16 bytes aligned */ template inline void pstoret(Scalar* to, const Packet& from) { if(LoadMode == Aligned) pstore(to, from); else pstoreu(to, from); } /** \internal default implementation of palign() allowing partial specialization */ template struct palign_impl { // by default data are aligned, so there is nothing to be done :) inline static void run(PacketType&, const PacketType&) {} }; /** \internal update \a first using the concatenation of the \a Offset last elements * of \a first and packet_size minus \a Offset first elements of \a second */ template inline void palign(PacketType& first, const PacketType& second) { palign_impl::run(first,second); } /*************************************************************************** * Fast complex products (GCC generates a function call which is very slow) ***************************************************************************/ template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } } // end namespace internal #endif // EIGEN_GENERIC_PACKET_MATH_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/GlobalFunctions.h000066400000000000000000000075631172143270300230100ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2010 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(NAME,FUNCTOR) \ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ NAME(const Eigen::ArrayBase& x) { \ return x.derived(); \ } #define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ \ template \ struct NAME##_retval > \ { \ typedef const Eigen::CwiseUnaryOp, const Derived> type; \ }; \ template \ struct NAME##_impl > \ { \ static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ { \ return x.derived(); \ } \ }; namespace std { EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(real,scalar_real_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(imag,scalar_imag_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sin,scalar_sin_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(cos,scalar_cos_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(asin,scalar_asin_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(acos,scalar_acos_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(tan,scalar_tan_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(exp,scalar_exp_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(log,scalar_log_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(abs,scalar_abs_op) EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sqrt,scalar_sqrt_op) template inline const Eigen::CwiseUnaryOp, const Derived> pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { \ return x.derived().pow(exponent); \ } } namespace Eigen { namespace internal { EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(sin,scalar_sin_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(cos,scalar_cos_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(asin,scalar_asin_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(acos,scalar_acos_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(tan,scalar_tan_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(exp,scalar_exp_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(log,scalar_log_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs,scalar_abs_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(sqrt,scalar_sqrt_op) } } // TODO: cleanly disable those functions that are not supported on Array (internal::real_ref, internal::random, internal::isApprox...) #endif // EIGEN_GLOBAL_FUNCTIONS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/IO.h000066400000000000000000000200471172143270300202160ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_IO_H #define EIGEN_IO_H enum { DontAlignCols = 1 }; enum { StreamPrecision = -1, FullPrecision = -2 }; namespace internal { template std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); } /** \class IOFormat * \ingroup Core_Module * * \brief Stores a set of parameters controlling the way matrices are printed * * List of available parameters: * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. * The default is the special value \c StreamPrecision which means to use the * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point * type. * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which * allows to disable the alignment of columns, resulting in faster code. * - \b coeffSeparator string printed between two coefficients of the same row * - \b rowSeparator string printed between two rows * - \b rowPrefix string printed at the beginning of each row * - \b rowSuffix string printed at the end of each row * - \b matPrefix string printed at the beginning of the matrix * - \b matSuffix string printed at the end of the matrix * * Example: \include IOFormat.cpp * Output: \verbinclude IOFormat.out * * \sa DenseBase::format(), class WithFormat */ struct IOFormat { /** Default contructor, see class IOFormat for the meaning of the parameters */ IOFormat(int _precision = StreamPrecision, int _flags = 0, const std::string& _coeffSeparator = " ", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", const std::string& _matPrefix="", const std::string& _matSuffix="") : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) { rowSpacer = ""; int i = int(matSuffix.length())-1; while (i>=0 && matSuffix[i]!='\n') { rowSpacer += ' '; i--; } } std::string matPrefix, matSuffix; std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; std::string coeffSeparator; int precision; int flags; }; /** \class WithFormat * \ingroup Core_Module * * \brief Pseudo expression providing matrix output with given format * * \param ExpressionType the type of the object on which IO stream operations are performed * * This class represents an expression with stream operators controlled by a given IOFormat. * It is the return type of DenseBase::format() * and most of the time this is the only way it is used. * * See class IOFormat for some examples. * * \sa DenseBase::format(), class IOFormat */ template class WithFormat { public: WithFormat(const ExpressionType& matrix, const IOFormat& format) : m_matrix(matrix), m_format(format) {} friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) { return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); } protected: const typename ExpressionType::Nested m_matrix; IOFormat m_format; }; /** \returns a WithFormat proxy object allowing to print a matrix the with given * format \a fmt. * * See class IOFormat for some examples. * * \sa class IOFormat, class WithFormat */ template inline const WithFormat DenseBase::format(const IOFormat& fmt) const { return WithFormat(derived(), fmt); } namespace internal { template struct significant_decimals_default_impl { typedef typename NumTraits::Real RealScalar; static inline int run() { return cast(std::ceil(-log(NumTraits::epsilon())/log(RealScalar(10)))); } }; template struct significant_decimals_default_impl { static inline int run() { return 0; } }; template struct significant_decimals_impl : significant_decimals_default_impl::IsInteger> {}; /** \internal * print the matrix \a _m to the output stream \a s using the output format \a fmt */ template std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) { if(_m.size() == 0) { s << fmt.matPrefix << fmt.matSuffix; return s; } const typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; Index width = 0; std::streamsize explicit_precision; if(fmt.precision == StreamPrecision) { explicit_precision = 0; } else if(fmt.precision == FullPrecision) { if (NumTraits::IsInteger) { explicit_precision = 0; } else { explicit_precision = significant_decimals_impl::run(); } } else { explicit_precision = fmt.precision; } bool align_cols = !(fmt.flags & DontAlignCols); if(align_cols) { // compute the largest width for(Index j = 1; j < m.cols(); ++j) for(Index i = 0; i < m.rows(); ++i) { std::stringstream sstr; if(explicit_precision) sstr.precision(explicit_precision); sstr << m.coeff(i,j); width = std::max(width, Index(sstr.str().length())); } } std::streamsize old_precision = 0; if(explicit_precision) old_precision = s.precision(explicit_precision); s << fmt.matPrefix; for(Index i = 0; i < m.rows(); ++i) { if (i) s << fmt.rowSpacer; s << fmt.rowPrefix; if(width) s.width(width); s << m.coeff(i, 0); for(Index j = 1; j < m.cols(); ++j) { s << fmt.coeffSeparator; if (width) s.width(width); s << m.coeff(i, j); } s << fmt.rowSuffix; if( i < m.rows() - 1) s << fmt.rowSeparator; } s << fmt.matSuffix; if(explicit_precision) s.precision(old_precision); return s; } } // end namespace internal /** \relates DenseBase * * Outputs the matrix, to the given stream. * * If you wish to print the matrix with a format different than the default, use DenseBase::format(). * * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. * * \sa DenseBase::format() */ template std::ostream & operator << (std::ostream & s, const DenseBase & m) { return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); } #endif // EIGEN_IO_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Map.h000066400000000000000000000211021172143270300204150ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MAP_H #define EIGEN_MAP_H /** \class Map * \ingroup Core_Module * * \brief A matrix or vector expression mapping an existing array of data. * * \param PlainObjectType the equivalent matrix type of the mapped data * \param MapOptions specifies whether the pointer is \c Aligned, or \c Unaligned. * The default is \c Unaligned. * \param StrideType optionnally specifies strides. By default, Map assumes the memory layout * of an ordinary, contiguous array. This can be overridden by specifying strides. * The type passed here must be a specialization of the Stride template, see examples below. * * This class represents a matrix or vector expression mapping an existing array of data. * It can be used to let Eigen interface without any overhead with non-Eigen data structures, * such as plain C arrays or structures from other libraries. By default, it assumes that the * data is laid out contiguously in memory. You can however override this by explicitly specifying * inner and outer strides. * * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix: * \include Map_simple.cpp * Output: \verbinclude Map_simple.out * * If you need to map non-contiguous arrays, you can do so by specifying strides: * * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time * fixed value. * \include Map_inner_stride.cpp * Output: \verbinclude Map_inner_stride.out * * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns. * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is * a short version of \c OuterStride because the default template parameter of OuterStride * is \c Dynamic * \include Map_outer_stride.cpp * Output: \verbinclude Map_outer_stride.out * * For more details and for an example of specifying both an inner and an outer stride, see class Stride. * * \b Tip: to change the array of data mapped by a Map object, you can use the C++ * placement new syntax: * * Example: \include Map_placement_new.cpp * Output: \verbinclude Map_placement_new.out * * This class is the return type of Matrix::Map() but can also be used directly. * * \sa Matrix::Map(), \ref TopicStorageOrders */ namespace internal { template struct traits > : public traits { typedef traits TraitsBase; typedef typename PlainObjectType::Index Index; typedef typename PlainObjectType::Scalar Scalar; enum { InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 ? int(PlainObjectType::InnerStrideAtCompileTime) : int(StrideType::InnerStrideAtCompileTime), OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 ? int(PlainObjectType::OuterStrideAtCompileTime) : int(StrideType::OuterStrideAtCompileTime), HasNoInnerStride = InnerStrideAtCompileTime == 1, HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, HasNoStride = HasNoInnerStride && HasNoOuterStride, IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, KeepsPacketAccess = bool(HasNoInnerStride) && ( bool(IsDynamicSize) || HasNoOuterStride || ( OuterStrideAtCompileTime!=Dynamic && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), Flags0 = TraitsBase::Flags, Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) ? int(Flags1) : int(Flags1 & ~LinearAccessBit), Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) }; private: enum { Options }; // Expressions don't have Options }; } template class Map : public MapBase > { public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Map) typedef typename Base::PointerType PointerType; #if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API typedef const Scalar* PointerArgType; inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } #else typedef PointerType PointerArgType; inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } #endif inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() : int(Flags)&RowMajorBit ? this->cols() : this->rows(); } /** Constructor in the fixed-size case. * * \param data pointer to the array to map * \param stride optional Stride object, passing the strides. */ inline Map(PointerArgType data, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(data)), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } /** Constructor in the dynamic-size vector case. * * \param data pointer to the array to map * \param size the size of the vector expression * \param stride optional Stride object, passing the strides. */ inline Map(PointerArgType data, Index size, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(data), size), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } /** Constructor in the dynamic-size matrix case. * * \param data pointer to the array to map * \param rows the number of rows of the matrix expression * \param cols the number of columns of the matrix expression * \param stride optional Stride object, passing the strides. */ inline Map(PointerArgType data, Index rows, Index cols, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(data), rows, cols), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) protected: StrideType m_stride; }; template inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> ::Array(const Scalar *data) { this->_set_noalias(Eigen::Map(data)); } template inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> ::Matrix(const Scalar *data) { this->_set_noalias(Eigen::Map(data)); } #endif // EIGEN_MAP_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/MapBase.h000066400000000000000000000213141172143270300212150ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MAPBASE_H #define EIGEN_MAPBASE_H #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) /** \class MapBase * \ingroup Core_Module * * \brief Base class for Map and Block expression with direct access * * \sa class Map, class Block */ template class MapBase : public internal::dense_xpr_base::type { public: typedef typename internal::dense_xpr_base::type Base; enum { RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, SizeAtCompileTime = Base::SizeAtCompileTime }; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef typename internal::conditional< bool(internal::is_lvalue::value), Scalar *, const Scalar *>::type PointerType; using Base::derived; // using Base::RowsAtCompileTime; // using Base::ColsAtCompileTime; // using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::IsRowMajor; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::eval; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; // bug 217 - compile error on ICC 11.1 using Base::operator=; typedef typename Base::CoeffReturnType CoeffReturnType; inline Index rows() const { return m_rows.value(); } inline Index cols() const { return m_cols.value(); } /** Returns a pointer to the first coefficient of the matrix or vector. * * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride(). * * \sa innerStride(), outerStride() */ inline const Scalar* data() const { return m_data; } inline const Scalar& coeff(Index row, Index col) const { return m_data[col * colStride() + row * rowStride()]; } inline const Scalar& coeff(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return m_data[index * innerStride()]; } inline const Scalar& coeffRef(Index row, Index col) const { return this->m_data[col * colStride() + row * rowStride()]; } inline const Scalar& coeffRef(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } template inline PacketScalar packet(Index row, Index col) const { return internal::ploadt (m_data + (col * colStride() + row * rowStride())); } template inline PacketScalar packet(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return internal::ploadt(m_data + index * innerStride()); } inline MapBase(PointerType data) : m_data(data), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) checkSanity(); } inline MapBase(PointerType data, Index size) : m_data(data), m_rows(RowsAtCompileTime == Dynamic ? size : Index(RowsAtCompileTime)), m_cols(ColsAtCompileTime == Dynamic ? size : Index(ColsAtCompileTime)) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) eigen_assert(size >= 0); eigen_assert(data == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == size); checkSanity(); } inline MapBase(PointerType data, Index rows, Index cols) : m_data(data), m_rows(rows), m_cols(cols) { eigen_assert( (data == 0) || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); checkSanity(); } protected: void checkSanity() const { EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % (sizeof(Scalar)*internal::packet_traits::size)) == 0) && "data is not aligned"); } PointerType m_data; const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; }; template class MapBase : public MapBase { public: typedef MapBase Base; typedef typename Base::Scalar Scalar; typedef typename Base::PacketScalar PacketScalar; typedef typename Base::Index Index; typedef typename Base::PointerType PointerType; using Base::derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; typedef typename internal::conditional< internal::is_lvalue::value, Scalar, const Scalar >::type ScalarWithConstIfNotLvalue; inline const Scalar* data() const { return this->m_data; } inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) { return this->m_data[col * colStride() + row * rowStride()]; } inline ScalarWithConstIfNotLvalue& coeffRef(Index index) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } template inline void writePacket(Index row, Index col, const PacketScalar& x) { internal::pstoret (this->m_data + (col * colStride() + row * rowStride()), x); } template inline void writePacket(Index index, const PacketScalar& x) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) internal::pstoret (this->m_data + index * innerStride(), x); } inline MapBase(PointerType data) : Base(data) {} inline MapBase(PointerType data, Index size) : Base(data, size) {} inline MapBase(PointerType data, Index rows, Index cols) : Base(data, rows, cols) {} Derived& operator=(const MapBase& other) { Base::Base::operator=(other); return derived(); } using Base::Base::operator=; }; #endif // EIGEN_MAPBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/MathFunctions.h000066400000000000000000000602311172143270300224700ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H namespace internal { /** \internal \struct global_math_functions_filtering_base * * What it does: * Defines a typedef 'type' as follows: * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then * global_math_functions_filtering_base::type is a typedef for it. * - otherwise, global_math_functions_filtering_base::type is a typedef for T. * * How it's used: * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. * * How it's implemented: * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace * the typename dummy by an integer template parameter, it doesn't work anymore! */ template struct global_math_functions_filtering_base { typedef T type; }; template struct always_void { typedef void type; }; template struct global_math_functions_filtering_base ::type > { typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; }; #define EIGEN_MATHFUNC_IMPL(func, scalar) func##_impl::type> #define EIGEN_MATHFUNC_RETVAL(func, scalar) typename func##_retval::type>::type /**************************************************************************** * Implementation of real * ****************************************************************************/ template struct real_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return x; } }; template struct real_impl > { static inline RealScalar run(const std::complex& x) { return std::real(x); } }; template struct real_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); } /**************************************************************************** * Implementation of imag * ****************************************************************************/ template struct imag_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar&) { return RealScalar(0); } }; template struct imag_impl > { static inline RealScalar run(const std::complex& x) { return std::imag(x); } }; template struct imag_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } /**************************************************************************** * Implementation of real_ref * ****************************************************************************/ template struct real_ref_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[0]; } static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[0]; } }; template struct real_ref_retval { typedef typename NumTraits::Real & type; }; template inline typename add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) { return real_ref_impl::run(x); } template inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } /**************************************************************************** * Implementation of imag_ref * ****************************************************************************/ template struct imag_ref_default_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[1]; } static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[1]; } }; template struct imag_ref_default_impl { static inline Scalar run(Scalar&) { return Scalar(0); } static inline const Scalar run(const Scalar&) { return Scalar(0); } }; template struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; template struct imag_ref_retval { typedef typename NumTraits::Real & type; }; template inline typename add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) { return imag_ref_impl::run(x); } template inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } /**************************************************************************** * Implementation of conj * ****************************************************************************/ template struct conj_impl { static inline Scalar run(const Scalar& x) { return x; } }; template struct conj_impl > { static inline std::complex run(const std::complex& x) { return std::conj(x); } }; template struct conj_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } /**************************************************************************** * Implementation of abs * ****************************************************************************/ template struct abs_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return std::abs(x); } }; template struct abs_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(abs, Scalar) abs(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs, Scalar)::run(x); } /**************************************************************************** * Implementation of abs2 * ****************************************************************************/ template struct abs2_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return x*x; } }; template struct abs2_impl > { static inline RealScalar run(const std::complex& x) { return std::norm(x); } }; template struct abs2_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } /**************************************************************************** * Implementation of norm1 * ****************************************************************************/ template struct norm1_default_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x) { return abs(real(x)) + abs(imag(x)); } }; template struct norm1_default_impl { static inline Scalar run(const Scalar& x) { return abs(x); } }; template struct norm1_impl : norm1_default_impl::IsComplex> {}; template struct norm1_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } /**************************************************************************** * Implementation of hypot * ****************************************************************************/ template struct hypot_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x, const Scalar& y) { RealScalar _x = abs(x); RealScalar _y = abs(y); RealScalar p = std::max(_x, _y); RealScalar q = std::min(_x, _y); RealScalar qp = q/p; return p * sqrt(RealScalar(1) + qp*qp); } }; template struct hypot_retval { typedef typename NumTraits::Real type; }; template inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } /**************************************************************************** * Implementation of cast * ****************************************************************************/ template struct cast_impl { static inline NewType run(const OldType& x) { return static_cast(x); } }; // here, for once, we're plainly returning NewType: we don't want cast to do weird things. template inline NewType cast(const OldType& x) { return cast_impl::run(x); } /**************************************************************************** * Implementation of sqrt * ****************************************************************************/ template struct sqrt_default_impl { static inline Scalar run(const Scalar& x) { return std::sqrt(x); } }; template struct sqrt_default_impl { static inline Scalar run(const Scalar&) { #ifdef EIGEN2_SUPPORT eigen_assert(!NumTraits::IsInteger); #else EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) #endif return Scalar(0); } }; template struct sqrt_impl : sqrt_default_impl::IsInteger> {}; template struct sqrt_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(sqrt, Scalar) sqrt(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(sqrt, Scalar)::run(x); } /**************************************************************************** * Implementation of standard unary real functions (exp, log, sin, cos, ... * ****************************************************************************/ // This macro instanciate all the necessary template mechanism which is common to all unary real functions. #define EIGEN_MATHFUNC_STANDARD_REAL_UNARY(NAME) \ template struct NAME##_default_impl { \ static inline Scalar run(const Scalar& x) { return std::NAME(x); } \ }; \ template struct NAME##_default_impl { \ static inline Scalar run(const Scalar&) { \ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) \ return Scalar(0); \ } \ }; \ template struct NAME##_impl \ : NAME##_default_impl::IsInteger> \ {}; \ template struct NAME##_retval { typedef Scalar type; }; \ template \ inline EIGEN_MATHFUNC_RETVAL(NAME, Scalar) NAME(const Scalar& x) { \ return EIGEN_MATHFUNC_IMPL(NAME, Scalar)::run(x); \ } EIGEN_MATHFUNC_STANDARD_REAL_UNARY(exp) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(log) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(sin) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(cos) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(tan) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(asin) EIGEN_MATHFUNC_STANDARD_REAL_UNARY(acos) /**************************************************************************** * Implementation of atan2 * ****************************************************************************/ template struct atan2_default_impl { typedef Scalar retval; static inline Scalar run(const Scalar& x, const Scalar& y) { return std::atan2(x, y); } }; template struct atan2_default_impl { static inline Scalar run(const Scalar&, const Scalar&) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) return Scalar(0); } }; template struct atan2_impl : atan2_default_impl::IsInteger> {}; template struct atan2_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(atan2, Scalar) atan2(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(atan2, Scalar)::run(x, y); } /**************************************************************************** * Implementation of pow * ****************************************************************************/ template struct pow_default_impl { typedef Scalar retval; static inline Scalar run(const Scalar& x, const Scalar& y) { return std::pow(x, y); } }; template struct pow_default_impl { static inline Scalar run(Scalar x, Scalar y) { Scalar res = 1; eigen_assert(!NumTraits::IsSigned || y >= 0); if(y & 1) res *= x; y >>= 1; while(y) { x *= x; if(y&1) res *= x; y >>= 1; } return res; } }; template struct pow_impl : pow_default_impl::IsInteger> {}; template struct pow_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); } /**************************************************************************** * Implementation of random * ****************************************************************************/ template struct random_default_impl {}; template struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; template struct random_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); template struct random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); } static inline Scalar run() { return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); } }; enum { floor_log2_terminate, floor_log2_move_up, floor_log2_move_down, floor_log2_bogus }; template struct floor_log2_selector { enum { middle = (lower + upper) / 2, value = (upper <= lower + 1) ? int(floor_log2_terminate) : (n < (1 << middle)) ? int(floor_log2_move_down) : (n==0) ? int(floor_log2_bogus) : int(floor_log2_move_up) }; }; template::value> struct floor_log2 {}; template struct floor_log2 { enum { value = floor_log2::middle>::value }; }; template struct floor_log2 { enum { value = floor_log2::middle, upper>::value }; }; template struct floor_log2 { enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; }; template struct floor_log2 { // no value, error at compile time }; template struct random_default_impl { typedef typename NumTraits::NonInteger NonInteger; static inline Scalar run(const Scalar& x, const Scalar& y) { return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); } static inline Scalar run() { #ifdef EIGEN_MAKING_DOCS return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); #else enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, scalar_bits = sizeof(Scalar) * CHAR_BIT, shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)) }; Scalar x = Scalar(std::rand() >> shift); Scalar offset = NumTraits::IsSigned ? Scalar(1 << (rand_bits-1)) : Scalar(0); return x - offset; #endif } }; template struct random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return Scalar(random(real(x), real(y)), random(imag(x), imag(y))); } static inline Scalar run() { typedef typename NumTraits::Real RealScalar; return Scalar(random(), random()); } }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); } template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } /**************************************************************************** * Implementation of fuzzy comparisons * ****************************************************************************/ template struct scalar_fuzzy_default_impl {}; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return abs(x) <= abs(y) * prec; } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return abs(x - y) <= std::min(abs(x), abs(y)) * prec; } static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) { return x <= y || isApprox(x, y, prec); } }; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) { return x == Scalar(0); } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) { return x == y; } static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) { return x <= y; } }; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return abs2(x) <= abs2(y) * prec * prec; } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return abs2(x - y) <= std::min(abs2(x), abs2(y)) * prec * prec; } }; template struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; template inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); } template inline bool isApprox(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApprox(x, y, precision); } template inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); } /****************************************** *** The special case of the bool type *** ******************************************/ template<> struct random_impl { static inline bool run() { return random(0,1)==0 ? false : true; } }; template<> struct scalar_fuzzy_impl { typedef bool RealScalar; template static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) { return !x; } static inline bool isApprox(bool x, bool y, bool) { return x == y; } static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) { return (!x) || y; } }; } // end namespace internal #endif // EIGEN_MATHFUNCTIONS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Matrix.h000066400000000000000000000445041172143270300211570ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008-2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MATRIX_H #define EIGEN_MATRIX_H /** \class Matrix * \ingroup Core_Module * * \brief The matrix class, also used for vectors and row-vectors * * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen. * Vectors are matrices with one column, and row-vectors are matrices with one row. * * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). * * The first three template parameters are required: * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * * The remaining template parameters are optional -- in most cases you don't have to worry about them. * \tparam _Options \anchor matrix_tparam_options A combination of either \b RowMajor or \b ColMajor, and of either * \b AutoAlign or \b DontAlign. * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note"). * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note"). * * Eigen provides a number of typedefs covering the usual cases. Here are some examples: * * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix) * \li \c Vector4f is a vector of 4 floats (\c Matrix) * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix) * * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix) * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix) * * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix) * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix) * * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs. * * You can access elements of vectors and matrices using normal subscripting: * * \code * Eigen::VectorXd v(10); * v[0] = 0.1; * v[1] = 0.2; * v(0) = 0.3; * v(1) = 0.4; * * Eigen::MatrixXi m(10, 10); * m(0, 1) = 1; * m(0, 2) = 2; * m(0, 3) = 3; * \endcode * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. * * Some notes: * *

*
\anchor dense Dense versus sparse:
*
This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module. * * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array. * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.
* *
\anchor fixedsize Fixed-size versus dynamic-size:
*
Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time. * * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime * variables, and the array of coefficients is allocated dynamically on the heap. * * Note that \em dense matrices, be they Fixed-size or Dynamic-size, do not expand dynamically in the sense of a std::map. * If you want this behavior, see the Sparse module.
* *
\anchor maxrows _MaxRows and _MaxCols:
*
In most cases, one just leaves these parameters to the default values. * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.
*
* * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, * \ref TopicStorageOrders */ namespace internal { template struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; typedef DenseIndex Index; typedef MatrixXpr XprKind; enum { RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _MaxRows, MaxColsAtCompileTime = _MaxCols, Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, CoeffReadCost = NumTraits::ReadCost, Options = _Options, InnerStrideAtCompileTime = 1, OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime }; }; } template class Matrix : public PlainObjectBase > { public: /** \brief Base class typedef. * \sa PlainObjectBase */ typedef PlainObjectBase Base; enum { Options = _Options }; EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) typedef typename Base::PlainObject PlainObject; enum { NeedsToAlign = (!(Options&DontAlign)) && SizeAtCompileTime!=Dynamic && ((static_cast(sizeof(Scalar))*SizeAtCompileTime)%16)==0 }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) using Base::base; using Base::coeffRef; /** * \brief Assigns matrices to each other. * * \note This is a special case of the templated operator=. Its purpose is * to prevent a default operator= from hiding the templated operator=. * * \callgraph */ EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { return Base::_set(other); } /** \internal * \brief Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) { return Base::_set(other); } /* Here, doxygen failed to copy the brief information when using \copydoc */ /** * \brief Copies the generic expression \a other into *this. * \copydetails DenseBase::operator=(const EigenBase &other) */ template EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) { return Base::operator=(other); } template EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { return Base::operator=(func); } /** \brief Default constructor. * * For fixed-size matrices, does nothing. * * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix * is called a null matrix. This constructor is the unique way to create null matrices: resizing * a matrix to 0 is not supported. * * \sa resize(Index,Index) */ EIGEN_STRONG_INLINE explicit Matrix() : Base() { Base::_check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } // FIXME is it still needed Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors * * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, * it is redundant to pass the dimension here, so it makes more sense to use the default * constructor Matrix() instead. */ EIGEN_STRONG_INLINE explicit Matrix(Index dim) : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) eigen_assert(dim >= 0); eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) { Base::_check_template_params(); Base::template _init2(x, y); } #else /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor * Matrix() instead. */ Matrix(Index rows, Index cols); /** \brief Constructs an initialized 2D vector with given coefficients */ Matrix(const Scalar& x, const Scalar& y); #endif /** \brief Constructs an initialized 3D vector with given coefficients */ EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; } /** \brief Constructs an initialized 4D vector with given coefficients */ EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; m_storage.data()[3] = w; } explicit Matrix(const Scalar *data); /** \brief Constructor copying the value of the expression \a other */ template EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) : Base(other.rows() * other.cols(), other.rows(), other.cols()) { // This test resides here, to bring the error messages closer to the user. Normally, these checks // are performed deeply within the library, thus causing long and scary error traces. EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) Base::_check_template_params(); Base::_set_noalias(other); } /** \brief Copy constructor */ EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other.rows() * other.cols(), other.rows(), other.cols()) { Base::_check_template_params(); Base::_set_noalias(other); } /** \brief Copy constructor with in-place evaluation */ template EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) { Base::_check_template_params(); Base::resize(other.rows(), other.cols()); other.evalTo(*this); } /** \brief Copy constructor for generic expressions. * \sa MatrixBase::operator=(const EigenBase&) */ template EIGEN_STRONG_INLINE Matrix(const EigenBase &other) : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) { Base::_check_template_params(); Base::resize(other.rows(), other.cols()); // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to // go for pure _set() implementations, right? *this = other; } /** \internal * \brief Override MatrixBase::swap() since for dynamic-sized matrices * of same type it is enough to swap the data pointers. */ template void swap(MatrixBase const & other) { this->_swap(other.derived()); } inline Index innerStride() const { return 1; } inline Index outerStride() const { return this->innerSize(); } /////////// Geometry module /////////// template explicit Matrix(const RotationBase& r); template Matrix& operator=(const RotationBase& r); #ifdef EIGEN2_SUPPORT template explicit Matrix(const eigen2_RotationBase& r); template Matrix& operator=(const eigen2_RotationBase& r); #endif // allow to extend Matrix outside Eigen #ifdef EIGEN_MATRIX_PLUGIN #include EIGEN_MATRIX_PLUGIN #endif protected: template friend struct internal::conservative_resize_like_impl; using Base::m_storage; }; /** \defgroup matrixtypedefs Global matrix typedefs * * \ingroup Core_Module * * Eigen defines several typedef shortcuts for most common matrix and vector types. * * The general patterns are the following: * * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd * for complex double. * * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats. * * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is * a fixed-size vector of 4 complex floats. * * \sa class Matrix */ #define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##SizeSuffix##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix Vector##SizeSuffix##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix RowVector##SizeSuffix##TypeSuffix; #define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##Size##X##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##X##Size##TypeSuffix; #define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cf) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) #undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES #undef EIGEN_MAKE_TYPEDEFS #undef EIGEN_MAKE_TYPEDEFS_LARGE #define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ using Eigen::Matrix##SizeSuffix##TypeSuffix; \ using Eigen::Vector##SizeSuffix##TypeSuffix; \ using Eigen::RowVector##SizeSuffix##TypeSuffix; #define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ #define EIGEN_USING_MATRIX_TYPEDEFS \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \ EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd) #endif // EIGEN_MATRIX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/MatrixBase.h000066400000000000000000000550741172143270300217560ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MATRIXBASE_H #define EIGEN_MATRIXBASE_H /** \class MatrixBase * \ingroup Core_Module * * \brief Base class for all dense matrices, vectors, and expressions * * This class is the base that is inherited by all matrix, vector, and related expression * types. Most of the Eigen API is contained in this class, and its base classes. Other important * classes for the Eigen API are Matrix, and VectorwiseOp. * * Note that some methods are defined in other modules such as the \ref LU_Module LU module * for all functions related to matrix inversions. * * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc. * * When writing a function taking Eigen objects as argument, if you want your function * to take as argument any matrix, vector, or expression, just let it take a * MatrixBase argument. As an example, here is a function printFirstRow which, given * a matrix, vector, or expression \a x, prints the first row of \a x. * * \code template void printFirstRow(const Eigen::MatrixBase& x) { cout << x.row(0) << endl; } * \endcode * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. * * \sa \ref TopicClassHierarchy */ template class MatrixBase : public DenseBase { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::CoeffReadCost; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::eval; using Base::operator+=; using Base::operator-=; using Base::operator*=; using Base::operator/=; typedef typename Base::CoeffReturnType CoeffReturnType; typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; typedef typename Base::RowXpr RowXpr; typedef typename Base::ColXpr ColXpr; #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN /** type of the equivalent square matrix */ typedef Matrix SquareMatrixType; #endif // not EIGEN_PARSED_BY_DOXYGEN /** \returns the size of the main diagonal, which is min(rows(),cols()). * \sa rows(), cols(), SizeAtCompileTime. */ inline Index diagonalSize() const { return std::min(rows(),cols()); } /** \brief The plain matrix type corresponding to this expression. * * This is not necessarily exactly the return type of eval(). In the case of plain matrices, * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed * that the return type of eval() is either PlainObject or const PlainObject&. */ typedef Matrix::Scalar, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime, AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), internal::traits::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime > PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Derived> ConstantReturnType; /** \internal the return type of MatrixBase::adjoint() */ typedef typename internal::conditional::IsComplex, CwiseUnaryOp, ConstTransposeReturnType>, ConstTransposeReturnType >::type AdjointReturnType; /** \internal Return type of eigenvalues() */ typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; /** \internal the return type of identity */ typedef CwiseNullaryOp,Derived> IdentityReturnType; /** \internal the return type of unit vectors */ typedef Block, SquareMatrixType>, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime> BasisReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/MatrixCwiseBinaryOps.h" # ifdef EIGEN_MATRIXBASE_PLUGIN # include EIGEN_MATRIXBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ Derived& operator=(const MatrixBase& other); // We cannot inherit here via Base::operator= since it is causing // trouble with MSVC. template Derived& operator=(const DenseBase& other); template Derived& operator=(const EigenBase& other); template Derived& operator=(const ReturnByValue& other); #ifndef EIGEN_PARSED_BY_DOXYGEN template Derived& lazyAssign(const ProductBase& other); #endif // not EIGEN_PARSED_BY_DOXYGEN template Derived& operator+=(const MatrixBase& other); template Derived& operator-=(const MatrixBase& other); template const typename ProductReturnType::Type operator*(const MatrixBase &other) const; template const typename LazyProductReturnType::Type lazyProduct(const MatrixBase &other) const; template Derived& operator*=(const EigenBase& other); template void applyOnTheLeft(const EigenBase& other); template void applyOnTheRight(const EigenBase& other); template const DiagonalProduct operator*(const DiagonalBase &diagonal) const; template typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType dot(const MatrixBase& other) const; #ifdef EIGEN2_SUPPORT template Scalar eigen2_dot(const MatrixBase& other) const; #endif RealScalar squaredNorm() const; RealScalar norm() const; RealScalar stableNorm() const; RealScalar blueNorm() const; RealScalar hypotNorm() const; const PlainObject normalized() const; void normalize(); const AdjointReturnType adjoint() const; void adjointInPlace(); typedef Diagonal DiagonalReturnType; DiagonalReturnType diagonal(); typedef const Diagonal ConstDiagonalReturnType; const ConstDiagonalReturnType diagonal() const; template struct DiagonalIndexReturnType { typedef Diagonal Type; }; template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; template typename DiagonalIndexReturnType::Type diagonal(); template typename ConstDiagonalIndexReturnType::Type diagonal() const; // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations. // On the other hand they confuse MSVC8... #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later typename MatrixBase::template DiagonalIndexReturnType::Type diagonal(Index index); typename MatrixBase::template ConstDiagonalIndexReturnType::Type diagonal(Index index) const; #else typename DiagonalIndexReturnType::Type diagonal(Index index); typename ConstDiagonalIndexReturnType::Type diagonal(Index index) const; #endif #ifdef EIGEN2_SUPPORT template typename internal::eigen2_part_return_type::type part(); template const typename internal::eigen2_part_return_type::type part() const; // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead // of an integer constant. Solution: overload the part() method template wrt template parameters list. template class U> const DiagonalWrapper part() const { return diagonal().asDiagonal(); } #endif // EIGEN2_SUPPORT template struct TriangularViewReturnType { typedef TriangularView Type; }; template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; template typename TriangularViewReturnType::Type triangularView(); template typename ConstTriangularViewReturnType::Type triangularView() const; template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; template typename SelfAdjointViewReturnType::Type selfadjointView(); template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; const SparseView sparseView(const Scalar& m_reference = Scalar(0), typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) const; static const IdentityReturnType Identity(); static const IdentityReturnType Identity(Index rows, Index cols); static const BasisReturnType Unit(Index size, Index i); static const BasisReturnType Unit(Index i); static const BasisReturnType UnitX(); static const BasisReturnType UnitY(); static const BasisReturnType UnitZ(); static const BasisReturnType UnitW(); const DiagonalWrapper asDiagonal() const; const PermutationWrapper asPermutation() const; Derived& setIdentity(); Derived& setIdentity(Index rows, Index cols); bool isIdentity(RealScalar prec = NumTraits::dummy_precision()) const; bool isDiagonal(RealScalar prec = NumTraits::dummy_precision()) const; bool isUpperTriangular(RealScalar prec = NumTraits::dummy_precision()) const; bool isLowerTriangular(RealScalar prec = NumTraits::dummy_precision()) const; template bool isOrthogonal(const MatrixBase& other, RealScalar prec = NumTraits::dummy_precision()) const; bool isUnitary(RealScalar prec = NumTraits::dummy_precision()) const; /** \returns true if each coefficients of \c *this and \a other are all exactly equal. * \warning When using floating point scalar values you probably should rather use a * fuzzy comparison such as isApprox() * \sa isApprox(), operator!= */ template inline bool operator==(const MatrixBase& other) const { return cwiseEqual(other).all(); } /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. * \warning When using floating point scalar values you probably should rather use a * fuzzy comparison such as isApprox() * \sa isApprox(), operator== */ template inline bool operator!=(const MatrixBase& other) const { return cwiseNotEqual(other).any(); } NoAlias noalias(); inline const ForceAlignedAccess forceAlignedAccess() const; inline ForceAlignedAccess forceAlignedAccess(); template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); Scalar trace() const; /////////// Array module /////////// template RealScalar lpNorm() const; MatrixBase& matrix() { return *this; } const MatrixBase& matrix() const { return *this; } /** \returns an \link ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ ArrayWrapper array() { return derived(); } const ArrayWrapper array() const { return derived(); } /////////// LU module /////////// const FullPivLU fullPivLu() const; const PartialPivLU partialPivLu() const; #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS const LU lu() const; #endif #ifdef EIGEN2_SUPPORT const LU eigen2_lu() const; #endif #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS const PartialPivLU lu() const; #endif #ifdef EIGEN2_SUPPORT template void computeInverse(MatrixBase *result) const { *result = this->inverse(); } #endif const internal::inverse_impl inverse() const; template void computeInverseAndDetWithCheck( ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template void computeInverseWithCheck( ResultType& inverse, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; Scalar determinant() const; /////////// Cholesky module /////////// const LLT llt() const; const LDLT ldlt() const; /////////// QR module /////////// const HouseholderQR householderQr() const; const ColPivHouseholderQR colPivHouseholderQr() const; const FullPivHouseholderQR fullPivHouseholderQr() const; #ifdef EIGEN2_SUPPORT const QR qr() const; #endif EigenvaluesReturnType eigenvalues() const; RealScalar operatorNorm() const; /////////// SVD module /////////// JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; #ifdef EIGEN2_SUPPORT SVD svd() const; #endif /////////// Geometry module /////////// #ifndef EIGEN_PARSED_BY_DOXYGEN /// \internal helper struct to form the return type of the cross product template struct cross_product_return_type { typedef typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; typedef Matrix type; }; #endif // EIGEN_PARSED_BY_DOXYGEN template typename cross_product_return_type::type cross(const MatrixBase& other) const; template PlainObject cross3(const MatrixBase& other) const; PlainObject unitOrthogonal(void) const; Matrix eulerAngles(Index a0, Index a1, Index a2) const; #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS ScalarMultipleReturnType operator*(const UniformScaling& s) const; // put this as separate enum value to work around possible GCC 4.3 bug (?) enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; typedef Homogeneous HomogeneousReturnType; HomogeneousReturnType homogeneous() const; #endif enum { SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 }; typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; typedef CwiseUnaryOp::Scalar>, const ConstStartMinusOne > HNormalizedReturnType; const HNormalizedReturnType hnormalized() const; ////////// Householder module /////////// void makeHouseholderInPlace(Scalar& tau, RealScalar& beta); template void makeHouseholder(EssentialPart& essential, Scalar& tau, RealScalar& beta) const; template void applyHouseholderOnTheLeft(const EssentialPart& essential, const Scalar& tau, Scalar* workspace); template void applyHouseholderOnTheRight(const EssentialPart& essential, const Scalar& tau, Scalar* workspace); ///////// Jacobi module ///////// template void applyOnTheLeft(Index p, Index q, const JacobiRotation& j); template void applyOnTheRight(Index p, Index q, const JacobiRotation& j); ///////// MatrixFunctions module ///////// typedef typename internal::stem_function::type StemFunction; const MatrixExponentialReturnValue exp() const; const MatrixFunctionReturnValue matrixFunction(StemFunction f) const; const MatrixFunctionReturnValue cosh() const; const MatrixFunctionReturnValue sinh() const; const MatrixFunctionReturnValue cos() const; const MatrixFunctionReturnValue sin() const; #ifdef EIGEN2_SUPPORT template Derived& operator+=(const Flagged, 0, EvalBeforeAssigningBit>& other); template Derived& operator-=(const Flagged, 0, EvalBeforeAssigningBit>& other); /** \deprecated because .lazy() is deprecated * Overloaded for cache friendly product evaluation */ template Derived& lazyAssign(const Flagged& other) { return lazyAssign(other._expression()); } template const Flagged marked() const; const Flagged lazy() const; inline const Cwise cwise() const; inline Cwise cwise(); VectorBlock start(Index size); const VectorBlock start(Index size) const; VectorBlock end(Index size); const VectorBlock end(Index size) const; template VectorBlock start(); template const VectorBlock start() const; template VectorBlock end(); template const VectorBlock end() const; Minor minor(Index row, Index col); const Minor minor(Index row, Index col) const; #endif protected: MatrixBase() : Base() {} private: explicit MatrixBase(int); MatrixBase(int,int); template explicit MatrixBase(const MatrixBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} // mixing arrays and matrices is not legal template Derived& operator-=(const ArrayBase& ) {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} }; #endif // EIGEN_MATRIXBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/NestByValue.h000066400000000000000000000075321172143270300221140ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_NESTBYVALUE_H #define EIGEN_NESTBYVALUE_H /** \class NestByValue * \ingroup Core_Module * * \brief Expression which must be nested by value * * \param ExpressionType the type of the object of which we are requiring nesting-by-value * * This class is the return type of MatrixBase::nestByValue() * and most of the time this is the only way it is used. * * \sa MatrixBase::nestByValue() */ namespace internal { template struct traits > : public traits {}; } template class NestByValue : public internal::dense_xpr_base< NestByValue >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } inline Index outerStride() const { return m_expression.outerStride(); } inline Index innerStride() const { return m_expression.innerStride(); } inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; }; /** \returns an expression of the temporary version of *this. */ template inline const NestByValue DenseBase::nestByValue() const { return NestByValue(derived()); } #endif // EIGEN_NESTBYVALUE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/NoAlias.h000066400000000000000000000133271172143270300212400ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_NOALIAS_H #define EIGEN_NOALIAS_H /** \class NoAlias * \ingroup Core_Module * * \brief Pseudo expression providing an operator = assuming no aliasing * * \param ExpressionType the type of the object on which to do the lazy assignment * * This class represents an expression with special assignment operators * assuming no aliasing between the target expression and the source expression. * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression. * It is the return type of MatrixBase::noalias() * and most of the time this is the only way it is used. * * \sa MatrixBase::noalias() */ template class StorageBase> class NoAlias { typedef typename ExpressionType::Scalar Scalar; public: NoAlias(ExpressionType& expression) : m_expression(expression) {} /** Behaves like MatrixBase::lazyAssign(other) * \sa MatrixBase::lazyAssign() */ template EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { return internal::assign_selector::run(m_expression,other.derived()); } /** \sa MatrixBase::operator+= */ template EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; SelfAdder tmp(m_expression); typedef typename internal::nested::type OtherDerivedNested; typedef typename internal::remove_all::type _OtherDerivedNested; internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); return m_expression; } /** \sa MatrixBase::operator-= */ template EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; SelfAdder tmp(m_expression); typedef typename internal::nested::type OtherDerivedNested; typedef typename internal::remove_all::type _OtherDerivedNested; internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); return m_expression; } #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) { other.derived().addTo(m_expression); return m_expression; } template EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) { other.derived().subTo(m_expression); return m_expression; } template EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } template EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } #endif protected: ExpressionType& m_expression; }; /** \returns a pseudo expression of \c *this with an operator= assuming * no aliasing between \c *this and the source expression. * * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag. * Currently, even though several expressions may alias, only product * expressions have this flag. Therefore, noalias() is only usefull when * the source expression contains a matrix product. * * Here are some examples where noalias is usefull: * \code * D.noalias() = A * B; * D.noalias() += A.transpose() * B; * D.noalias() -= 2 * A * B.adjoint(); * \endcode * * On the other hand the following example will lead to a \b wrong result: * \code * A.noalias() = A * B; * \endcode * because the result matrix A is also an operand of the matrix product. Therefore, * there is no alternative than evaluating A * B in a temporary, that is the default * behavior when you write: * \code * A = A * B; * \endcode * * \sa class NoAlias */ template NoAlias MatrixBase::noalias() { return derived(); } #endif // EIGEN_NOALIAS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/NumTraits.h000066400000000000000000000153541172143270300216420ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_NUMTRAITS_H #define EIGEN_NUMTRAITS_H /** \class NumTraits * \ingroup Core_Module * * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * * \param T the numeric type at hand * * This class stores enums, typedefs and static methods giving information about a numeric type. * * The provided data consists of: * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real * is a typedef to \a U. * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is * only intended as a helper for code that needs to explicitly promote types. * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex * type, and to 0 otherwise. * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, * and to \c 0 otherwise. * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. * Stay vague here. No need to do architecture-specific stuff. * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default * value by the fuzzy comparison operators. * \li highest() and lowest() functions returning the highest and lowest possible values respectively. */ template struct GenericNumTraits { enum { IsInteger = std::numeric_limits::is_integer, IsSigned = std::numeric_limits::is_signed, IsComplex = 0, RequireInitialization = internal::is_arithmetic::value ? 0 : 1, ReadCost = 1, AddCost = 1, MulCost = 1 }; typedef T Real; typedef typename internal::conditional< IsInteger, typename internal::conditional::type, T >::type NonInteger; typedef T Nested; inline static Real epsilon() { return std::numeric_limits::epsilon(); } inline static Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } inline static T highest() { return std::numeric_limits::max(); } inline static T lowest() { return IsInteger ? std::numeric_limits::min() : (-std::numeric_limits::max()); } #ifdef EIGEN2_SUPPORT enum { HasFloatingPoint = !IsInteger }; typedef NonInteger FloatingPoint; #endif }; template struct NumTraits : GenericNumTraits {}; template<> struct NumTraits : GenericNumTraits { inline static float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { inline static double dummy_precision() { return 1e-12; } }; template<> struct NumTraits : GenericNumTraits { static inline long double dummy_precision() { return 1e-15l; } }; template struct NumTraits > : GenericNumTraits > { typedef _Real Real; enum { IsComplex = 1, RequireInitialization = NumTraits<_Real>::RequireInitialization, ReadCost = 2 * NumTraits<_Real>::ReadCost, AddCost = 2 * NumTraits::AddCost, MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; inline static Real epsilon() { return NumTraits::epsilon(); } inline static Real dummy_precision() { return NumTraits::dummy_precision(); } }; template struct NumTraits > { typedef Array ArrayType; typedef typename NumTraits::Real RealScalar; typedef Array Real; typedef typename NumTraits::NonInteger NonIntegerScalar; typedef Array NonInteger; typedef ArrayType & Nested; enum { IsComplex = NumTraits::IsComplex, IsInteger = NumTraits::IsInteger, IsSigned = NumTraits::IsSigned, RequireInitialization = 1, ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost }; }; #endif // EIGEN_NUMTRAITS_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/PermutationMatrix.h000066400000000000000000000575671172143270300234240ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009-2011 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_PERMUTATIONMATRIX_H #define EIGEN_PERMUTATIONMATRIX_H template class PermutedImpl; /** \class PermutationBase * \ingroup Core_Module * * \brief Base class for permutations * * \param Derived the derived class * * This class is the base class for all expressions representing a permutation matrix, * internally stored as a vector of integers. * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have: * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f] * * Permutation matrices are square and invertible. * * Notice that in addition to the member functions and operators listed here, there also are non-member * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) * on either side. * * \sa class PermutationMatrix, class PermutationWrapper */ namespace internal { template struct permut_matrix_product_retval; enum PermPermProduct_t {PermPermProduct}; } // end namespace internal template class PermutationBase : public EigenBase { typedef internal::traits Traits; typedef EigenBase Base; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, CoeffReadCost = Traits::CoeffReadCost, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; typedef typename Traits::Scalar Scalar; typedef typename Traits::Index Index; typedef Matrix DenseMatrixType; typedef PermutationMatrix PlainPermutationType; using Base::derived; #endif /** Copies the other permutation into *this */ template Derived& operator=(const PermutationBase& other) { indices() = other.indices(); return derived(); } /** Assignment from the Transpositions \a tr */ template Derived& operator=(const TranspositionsBase& tr) { setIdentity(tr.size()); for(Index k=size()-1; k>=0; --k) applyTranspositionOnTheRight(k,tr.coeff(k)); return derived(); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ Derived& operator=(const PermutationBase& other) { indices() = other.indices(); return derived(); } #endif /** \returns the number of rows */ inline Index rows() const { return indices().size(); } /** \returns the number of columns */ inline Index cols() const { return indices().size(); } /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ inline Index size() const { return indices().size(); } #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); for (int i=0; i=0 && j>=0 && i=0 && j>=0 && i inverse() const { return derived(); } /** \returns the tranpose permutation matrix. * * \note \note_try_to_help_rvo */ inline Transpose transpose() const { return derived(); } /**** multiplication helpers to hopefully get RVO ****/ #ifndef EIGEN_PARSED_BY_DOXYGEN protected: template void assignTranspose(const PermutationBase& other) { for (int i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); for (int i=0; i inline PlainPermutationType operator*(const PermutationBase& other) const { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } /** \returns the product of a permutation with another inverse permutation. * * \note \note_try_to_help_rvo */ template inline PlainPermutationType operator*(const Transpose >& other) const { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. * * \note \note_try_to_help_rvo */ template friend inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } protected: }; /** \class PermutationMatrix * \ingroup Core_Module * * \brief Permutation matrix * * \param SizeAtCompileTime the number of rows/cols, or Dynamic * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. * \param IndexType the interger type of the indices * * This class represents a permutation matrix, internally stored as a vector of integers. * * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix */ namespace internal { template struct traits > : traits > { typedef IndexType Index; typedef Matrix IndicesType; }; } template class PermutationMatrix : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; #endif inline PermutationMatrix() {} /** Constructs an uninitialized permutation matrix of given size. */ inline PermutationMatrix(int size) : m_indices(size) {} /** Copy constructor. */ template inline PermutationMatrix(const PermutationBase& other) : m_indices(other.indices()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN /** Standard copy constructor. Defined only to prevent a default copy constructor * from hiding the other templated constructor */ inline PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} #endif /** Generic constructor from expression of the indices. The indices * array has the meaning that the permutations sends each integer i to indices[i]. * * \warning It is your responsibility to check that the indices array that you passes actually * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the * array's size. */ template explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) {} /** Convert the Transpositions \a tr to a permutation matrix */ template explicit PermutationMatrix(const TranspositionsBase& tr) : m_indices(tr.size()) { *this = tr; } /** Copies the other permutation into *this */ template PermutationMatrix& operator=(const PermutationBase& other) { m_indices = other.indices(); return *this; } /** Assignment from the Transpositions \a tr */ template PermutationMatrix& operator=(const TranspositionsBase& tr) { return Base::operator=(tr.derived()); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ PermutationMatrix& operator=(const PermutationMatrix& other) { m_indices = other.m_indices; return *this; } #endif /** const version of indices(). */ const IndicesType& indices() const { return m_indices; } /** \returns a reference to the stored array representing the permutation. */ IndicesType& indices() { return m_indices; } /**** multiplication helpers to hopefully get RVO ****/ #ifndef EIGEN_PARSED_BY_DOXYGEN template PermutationMatrix(const Transpose >& other) : m_indices(other.nestedPermutation().size()) { for (int i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) : m_indices(lhs.indices().size()) { Base::assignProduct(lhs,rhs); } #endif protected: IndicesType m_indices; }; namespace internal { template struct traits,_PacketAccess> > : traits > { typedef IndexType Index; typedef Map, _PacketAccess> IndicesType; }; } template class Map,_PacketAccess> : public PermutationBase,_PacketAccess> > { typedef PermutationBase Base; typedef internal::traits Traits; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; typedef typename IndicesType::Scalar Index; #endif inline Map(const Index* indices) : m_indices(indices) {} inline Map(const Index* indices, Index size) : m_indices(indices,size) {} /** Copies the other permutation into *this */ template Map& operator=(const PermutationBase& other) { return Base::operator=(other.derived()); } /** Assignment from the Transpositions \a tr */ template Map& operator=(const TranspositionsBase& tr) { return Base::operator=(tr.derived()); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ Map& operator=(const Map& other) { m_indices = other.m_indices; return *this; } #endif /** const version of indices(). */ const IndicesType& indices() const { return m_indices; } /** \returns a reference to the stored array representing the permutation. */ IndicesType& indices() { return m_indices; } protected: IndicesType m_indices; }; /** \class PermutationWrapper * \ingroup Core_Module * * \brief Class to view a vector of integers as a permutation matrix * * \param _IndicesType the type of the vector of integer (can be any compatible expression) * * This class allows to view any vector expression of integers as a permutation matrix. * * \sa class PermutationBase, class PermutationMatrix */ struct PermutationStorage {}; template class TranspositionsWrapper; namespace internal { template struct traits > { typedef PermutationStorage StorageKind; typedef typename _IndicesType::Scalar Scalar; typedef typename _IndicesType::Scalar Index; typedef _IndicesType IndicesType; enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, Flags = 0, CoeffReadCost = _IndicesType::CoeffReadCost }; }; } template class PermutationWrapper : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; #endif inline PermutationWrapper(const IndicesType& indices) : m_indices(indices) {} /** const version of indices(). */ const typename internal::remove_all::type& indices() const { return m_indices; } protected: const typename IndicesType::Nested m_indices; }; /** \returns the matrix with the permutation applied to the columns. */ template inline const internal::permut_matrix_product_retval operator*(const MatrixBase& matrix, const PermutationBase &permutation) { return internal::permut_matrix_product_retval (permutation.derived(), matrix.derived()); } /** \returns the matrix with the permutation applied to the rows. */ template inline const internal::permut_matrix_product_retval operator*(const PermutationBase &permutation, const MatrixBase& matrix) { return internal::permut_matrix_product_retval (permutation.derived(), matrix.derived()); } namespace internal { template struct traits > { typedef typename MatrixType::PlainObject ReturnType; }; template struct permut_matrix_product_retval : public ReturnByValue > { typedef typename remove_all::type MatrixTypeNestedCleaned; permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) : m_permutation(perm), m_matrix(matrix) {} inline int rows() const { return m_matrix.rows(); } inline int cols() const { return m_matrix.cols(); } template inline void evalTo(Dest& dst) const { const int n = Side==OnTheLeft ? rows() : cols(); if(is_same::value && extract_data(dst) == extract_data(m_matrix)) { // apply the permutation inplace Matrix mask(m_permutation.size()); mask.fill(false); int r = 0; while(r < m_permutation.size()) { // search for the next seed while(r=m_permutation.size()) break; // we got one, let's follow it until we are back to the seed int k0 = r++; int kPrev = k0; mask.coeffRef(k0) = true; for(int k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) { Block(dst, k) .swap(Block (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); mask.coeffRef(k) = true; kPrev = k; } } } else { for(int i = 0; i < n; ++i) { Block (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) = Block (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); } } } protected: const PermutationType& m_permutation; const typename MatrixType::Nested m_matrix; }; /* Template partial specialization for transposed/inverse permutations */ template struct traits > > : traits {}; } // end namespace internal template class Transpose > : public EigenBase > > { typedef Derived PermutationType; typedef typename PermutationType::IndicesType IndicesType; typedef typename PermutationType::PlainPermutationType PlainPermutationType; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef internal::traits Traits; typedef typename Derived::DenseMatrixType DenseMatrixType; enum { Flags = Traits::Flags, CoeffReadCost = Traits::CoeffReadCost, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; typedef typename Traits::Scalar Scalar; #endif Transpose(const PermutationType& p) : m_permutation(p) {} inline int rows() const { return m_permutation.rows(); } inline int cols() const { return m_permutation.cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); for (int i=0; i friend inline const internal::permut_matrix_product_retval operator*(const MatrixBase& matrix, const Transpose& trPerm) { return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ template inline const internal::permut_matrix_product_retval operator*(const MatrixBase& matrix) const { return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); } const PermutationType& nestedPermutation() const { return m_permutation; } protected: const PermutationType& m_permutation; }; template const PermutationWrapper MatrixBase::asPermutation() const { return derived(); } #endif // EIGEN_PERMUTATIONMATRIX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/PlainObjectBase.h000066400000000000000000000770751172143270300227110ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_DENSESTORAGEBASE_H #define EIGEN_DENSESTORAGEBASE_H #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO # define EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED for(int i=0;i(Derived::IsVectorAtCompileTime)> struct conservative_resize_like_impl; template struct matrix_swap_impl; } // end namespace internal /** * \brief %Dense storage base class for matrices and arrays. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. * * \sa \ref TopicClassHierarchy */ template class PlainObjectBase : public internal::dense_xpr_base::type { public: enum { Options = internal::traits::Options }; typedef typename internal::dense_xpr_base::type Base; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef Derived DenseType; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; template friend class Eigen::Map; friend class Eigen::Map; typedef Eigen::Map MapType; friend class Eigen::Map; typedef const Eigen::Map ConstMapType; friend class Eigen::Map; typedef Eigen::Map AlignedMapType; friend class Eigen::Map; typedef const Eigen::Map ConstAlignedMapType; template struct StridedMapType { typedef Eigen::Map type; }; template struct StridedConstMapType { typedef Eigen::Map type; }; template struct StridedAlignedMapType { typedef Eigen::Map type; }; template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; protected: DenseStorage m_storage; public: enum { NeedsToAlign = (!(Options&DontAlign)) && SizeAtCompileTime!=Dynamic && ((static_cast(sizeof(Scalar))*SizeAtCompileTime)%16)==0 }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) Base& base() { return *static_cast(this); } const Base& base() const { return *static_cast(this); } EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } EIGEN_STRONG_INLINE const Scalar& coeff(Index row, Index col) const { if(Flags & RowMajorBit) return m_storage.data()[col + row * m_storage.cols()]; else // column-major return m_storage.data()[row + col * m_storage.rows()]; } EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { return m_storage.data()[index]; } EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { if(Flags & RowMajorBit) return m_storage.data()[col + row * m_storage.cols()]; else // column-major return m_storage.data()[row + col * m_storage.rows()]; } EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_storage.data()[index]; } EIGEN_STRONG_INLINE const Scalar& coeffRef(Index row, Index col) const { if(Flags & RowMajorBit) return m_storage.data()[col + row * m_storage.cols()]; else // column-major return m_storage.data()[row + col * m_storage.rows()]; } EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const { return m_storage.data()[index]; } /** \internal */ template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { return internal::ploadt (m_storage.data() + (Flags & RowMajorBit ? col + row * m_storage.cols() : row + col * m_storage.rows())); } /** \internal */ template EIGEN_STRONG_INLINE PacketScalar packet(Index index) const { return internal::ploadt(m_storage.data() + index); } /** \internal */ template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketScalar& x) { internal::pstoret (m_storage.data() + (Flags & RowMajorBit ? col + row * m_storage.cols() : row + col * m_storage.rows()), x); } /** \internal */ template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& x) { internal::pstoret(m_storage.data() + index, x); } /** \returns a const pointer to the data array of this matrix */ EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. * * This method is intended for dynamic-size matrices, although it is legal to call it on any * matrix as long as fixed dimensions are left unchanged. If you only want to change the number * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t). * * If the current number of coefficients of \c *this exactly matches the * product \a rows * \a cols, then no memory allocation is performed and * the current values are left unchanged. In all other cases, including * shrinking, the data is reallocated and all previous values are lost. * * Example: \include Matrix_resize_int_int.cpp * Output: \verbinclude Matrix_resize_int_int.out * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ EIGEN_STRONG_INLINE void resize(Index rows, Index cols) { #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO Index size = rows*cols; bool size_changed = size != this->size(); m_storage.resize(size, rows, cols); if(size_changed) EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED #else m_storage.resize(rows*cols, rows, cols); #endif } /** Resizes \c *this to a vector of length \a size * * \only_for_vectors. This method does not work for * partially dynamic matrices when the static dimension is anything other * than 1. For example it will not work with Matrix. * * Example: \include Matrix_resize_int.cpp * Output: \verbinclude Matrix_resize_int.out * * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) */ inline void resize(Index size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == size); #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO bool size_changed = size != this->size(); #endif if(RowsAtCompileTime == 1) m_storage.resize(size, 1, size); else m_storage.resize(size, size, 1); #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO if(size_changed) EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED #endif } /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange * as in the example below. * * Example: \include Matrix_resize_NoChange_int.cpp * Output: \verbinclude Matrix_resize_NoChange_int.out * * \sa resize(Index,Index) */ inline void resize(NoChange_t, Index cols) { resize(rows(), cols); } /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange * as in the example below. * * Example: \include Matrix_resize_int_NoChange.cpp * Output: \verbinclude Matrix_resize_int_NoChange.out * * \sa resize(Index,Index) */ inline void resize(Index rows, NoChange_t) { resize(rows, cols()); } /** Resizes \c *this to have the same dimensions as \a other. * Takes care of doing all the checking that's needed. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) { const OtherDerived& other = _other.derived(); const Index othersize = other.rows()*other.cols(); if(RowsAtCompileTime == 1) { eigen_assert(other.rows() == 1 || other.cols() == 1); resize(1, othersize); } else if(ColsAtCompileTime == 1) { eigen_assert(other.rows() == 1 || other.cols() == 1); resize(othersize, 1); } else resize(other.rows(), other.cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * The method is intended for matrices of dynamic size. If you only want to change the number * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or * conservativeResize(Index, NoChange_t). * * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will be uninitialized. */ EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) { internal::conservative_resize_like_impl::run(*this, rows, cols); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * As opposed to conservativeResize(Index rows, Index cols), this version leaves * the number of columns unchanged. * * In case the matrix is growing, new rows will be uninitialized. */ EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) { // Note: see the comment in conservativeResize(Index,Index) conservativeResize(rows, cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * As opposed to conservativeResize(Index rows, Index cols), this version leaves * the number of rows unchanged. * * In case the matrix is growing, new columns will be uninitialized. */ EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) { // Note: see the comment in conservativeResize(Index,Index) conservativeResize(rows(), cols); } /** Resizes the vector to \a size while retaining old values. * * \only_for_vectors. This method does not work for * partially dynamic matrices when the static dimension is anything other * than 1. For example it will not work with Matrix. * * When values are appended, they will be uninitialized. */ EIGEN_STRONG_INLINE void conservativeResize(Index size) { internal::conservative_resize_like_impl::run(*this, size); } /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched. * * The method is intended for matrices of dynamic size. If you only want to change the number * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or * conservativeResize(Index, NoChange_t). * * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will copied from \c other. */ template EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) { internal::conservative_resize_like_impl::run(*this, other); } /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) { return _set(other); } /** \sa MatrixBase::lazyAssign() */ template EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) { _resize_to_match(other); return Base::lazyAssign(other.derived()); } template EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); } EIGEN_STRONG_INLINE explicit PlainObjectBase() : m_storage() { // _check_template_params(); // EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ? /** \internal */ PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } #endif EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) : m_storage(size, rows, cols) { // _check_template_params(); // EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } /** \copydoc MatrixBase::operator=(const EigenBase&) */ template EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) { _resize_to_match(other); Base::operator=(other.derived()); return this->derived(); } /** \sa MatrixBase::operator=(const EigenBase&) */ template EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) { _check_template_params(); Base::operator=(other.derived()); } /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned * \a data pointers. * * These methods do not allow to specify strides. If you need to specify strides, you have to * use the Map class directly. * * \see class Map */ //@{ inline static ConstMapType Map(const Scalar* data) { return ConstMapType(data); } inline static MapType Map(Scalar* data) { return MapType(data); } inline static ConstMapType Map(const Scalar* data, Index size) { return ConstMapType(data, size); } inline static MapType Map(Scalar* data, Index size) { return MapType(data, size); } inline static ConstMapType Map(const Scalar* data, Index rows, Index cols) { return ConstMapType(data, rows, cols); } inline static MapType Map(Scalar* data, Index rows, Index cols) { return MapType(data, rows, cols); } inline static ConstAlignedMapType MapAligned(const Scalar* data) { return ConstAlignedMapType(data); } inline static AlignedMapType MapAligned(Scalar* data) { return AlignedMapType(data); } inline static ConstAlignedMapType MapAligned(const Scalar* data, Index size) { return ConstAlignedMapType(data, size); } inline static AlignedMapType MapAligned(Scalar* data, Index size) { return AlignedMapType(data, size); } inline static ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) { return ConstAlignedMapType(data, rows, cols); } inline static AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) { return AlignedMapType(data, rows, cols); } template inline static typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) { return typename StridedConstMapType >::type(data, stride); } template inline static typename StridedMapType >::type Map(Scalar* data, const Stride& stride) { return typename StridedMapType >::type(data, stride); } template inline static typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstMapType >::type(data, size, stride); } template inline static typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) { return typename StridedMapType >::type(data, size, stride); } template inline static typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstMapType >::type(data, rows, cols, stride); } template inline static typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedMapType >::type(data, rows, cols, stride); } template inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, stride); } template inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) { return typename StridedAlignedMapType >::type(data, stride); } template inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, size, stride); } template inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) { return typename StridedAlignedMapType >::type(data, size, stride); } template inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } template inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } //@} using Base::setConstant; Derived& setConstant(Index size, const Scalar& value); Derived& setConstant(Index rows, Index cols, const Scalar& value); using Base::setZero; Derived& setZero(Index size); Derived& setZero(Index rows, Index cols); using Base::setOnes; Derived& setOnes(Index size); Derived& setOnes(Index rows, Index cols); using Base::setRandom; Derived& setRandom(Index size); Derived& setRandom(Index rows, Index cols); #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN #include EIGEN_PLAINOBJECTBASE_PLUGIN #endif protected: /** \internal Resizes *this in preparation for assigning \a other to it. * Takes care of doing all the checking that's needed. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size()) : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); #else resizeLike(other); #endif } /** * \brief Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. * * \sa operator=(const MatrixBase&), _set_noalias() * * \internal */ template EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) { _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); return this->derived(); } template EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } template EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * * \sa operator=(const MatrixBase&), _set() */ template EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { // I don't think we need this resize call since the lazyAssign will anyways resize // and lazyAssign will be called by the assign selector. //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. return internal::assign_selector::run(this->derived(), other.derived()); } template EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) { eigen_assert(rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); m_storage.resize(rows*cols,rows,cols); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED } template EIGEN_STRONG_INLINE void _init2(const Scalar& x, const Scalar& y, typename internal::enable_if::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) m_storage.data()[0] = x; m_storage.data()[1] = y; } template friend struct internal::matrix_swap_impl; /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the * data pointers. */ template void _swap(DenseBase const & other) { enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); } public: #ifndef EIGEN_PARSED_BY_DOXYGEN EIGEN_STRONG_INLINE static void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0) && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0)) && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0)) && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0)) && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0)) && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic) && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic) && (Options & (DontAlign|RowMajor)) == Options), INVALID_MATRIX_TEMPLATE_PARAMETERS) } #endif private: enum { ThisConstantIsPrivateInPlainObjectBase }; }; template struct internal::conservative_resize_like_impl { typedef typename Derived::Index Index; static void run(DenseBase& _this, Index rows, Index cols) { if (_this.rows() == rows && _this.cols() == cols) return; EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) if ( ( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows (!Derived::IsRowMajor && _this.rows() == rows) ) // column-major and we change only the number of columns { _this.derived().m_storage.conservativeResize(rows*cols,rows,cols); } else { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(rows,cols); const Index common_rows = std::min(rows, _this.rows()); const Index common_cols = std::min(cols, _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } } static void run(DenseBase& _this, const DenseBase& other) { if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index), // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) if ( ( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows (!Derived::IsRowMajor && _this.rows() == other.rows()) ) // column-major and we change only the number of columns { const Index new_rows = other.rows() - _this.rows(); const Index new_cols = other.cols() - _this.cols(); _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols()); if (new_rows>0) _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows); else if (new_cols>0) _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols); } else { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(other); const Index common_rows = std::min(tmp.rows(), _this.rows()); const Index common_cols = std::min(tmp.cols(), _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } } }; namespace internal { template struct conservative_resize_like_impl { typedef typename Derived::Index Index; static void run(DenseBase& _this, Index size) { const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1; _this.derived().m_storage.conservativeResize(size,new_rows,new_cols); } static void run(DenseBase& _this, const DenseBase& other) { if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; const Index num_new_elements = other.size() - _this.size(); const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows(); const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1; _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols); if (num_new_elements > 0) _this.tail(num_new_elements) = other.tail(num_new_elements); } }; template struct matrix_swap_impl { static inline void run(MatrixTypeA& a, MatrixTypeB& b) { a.base().swap(b); } }; template struct matrix_swap_impl { static inline void run(MatrixTypeA& a, MatrixTypeB& b) { static_cast(a).m_storage.swap(static_cast(b).m_storage); } }; } // end namespace internal #endif // EIGEN_DENSESTORAGEBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Product.h000066400000000000000000000655411172143270300213370ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_PRODUCT_H #define EIGEN_PRODUCT_H /** \class GeneralProduct * \ingroup Core_Module * * \brief Expression of the product of two general matrices or vectors * * \param LhsNested the type used to store the left-hand side * \param RhsNested the type used to store the right-hand side * \param ProductMode the type of the product * * This class represents an expression of the product of two general matrices. * We call a general matrix, a dense matrix with full storage. For instance, * This excludes triangular, selfadjoint, and sparse matrices. * It is the return type of the operator* between general matrices. Its template * arguments are determined automatically by ProductReturnType. Therefore, * GeneralProduct should never be used direclty. To determine the result type of a * function which involves a matrix product, use ProductReturnType::Type. * * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) */ template::value> class GeneralProduct; enum { Large = 2, Small = 3 }; namespace internal { template struct product_type_selector; template struct product_size_category { enum { is_large = MaxSize == Dynamic || Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, value = is_large ? Large : Size == 1 ? 1 : Small }; }; template struct product_type { typedef typename remove_all::type _Lhs; typedef typename remove_all::type _Rhs; enum { MaxRows = _Lhs::MaxRowsAtCompileTime, Rows = _Lhs::RowsAtCompileTime, MaxCols = _Rhs::MaxColsAtCompileTime, Cols = _Rhs::ColsAtCompileTime, MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, _Rhs::MaxRowsAtCompileTime), Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, _Rhs::RowsAtCompileTime), LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD }; // the splitting into different lines of code here, introducing the _select enums and the typedef below, // is to work around an internal compiler error with gcc 4.1 and 4.2. private: enum { rows_select = product_size_category::value, cols_select = product_size_category::value, depth_select = product_size_category::value }; typedef product_type_selector selector; public: enum { value = selector::ret }; #ifdef EIGEN_DEBUG_PRODUCT static void debug() { EIGEN_DEBUG_VAR(Rows); EIGEN_DEBUG_VAR(Cols); EIGEN_DEBUG_VAR(Depth); EIGEN_DEBUG_VAR(rows_select); EIGEN_DEBUG_VAR(cols_select); EIGEN_DEBUG_VAR(depth_select); EIGEN_DEBUG_VAR(value); } #endif }; /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ // FIXME I'm not sure the current mapping is the ideal one. template struct product_type_selector { enum { ret = OuterProduct }; }; template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemvProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; } // end namespace internal /** \class ProductReturnType * \ingroup Core_Module * * \brief Helper class to get the correct and optimized returned type of operator* * * \param Lhs the type of the left-hand side * \param Rhs the type of the right-hand side * \param ProductMode the type of the product (determined automatically by internal::product_mode) * * This class defines the typename Type representing the optimized product expression * between two matrix expressions. In practice, using ProductReturnType::Type * is the recommended way to define the result type of a function returning an expression * which involve a matrix product. The class Product should never be * used directly. * * \sa class Product, MatrixBase::operator*(const MatrixBase&) */ template struct ProductReturnType { // TODO use the nested type to reduce instanciations ???? // typedef typename internal::nested::type LhsNested; // typedef typename internal::nested::type RhsNested; typedef GeneralProduct Type; }; template struct ProductReturnType { typedef typename internal::nested::type >::type LhsNested; typedef typename internal::nested::type >::type RhsNested; typedef CoeffBasedProduct Type; }; template struct ProductReturnType { typedef typename internal::nested::type >::type LhsNested; typedef typename internal::nested::type >::type RhsNested; typedef CoeffBasedProduct Type; }; // this is a workaround for sun CC template struct LazyProductReturnType : public ProductReturnType {}; /*********************************************************************** * Implementation of Inner Vector Vector Product ***********************************************************************/ // FIXME : maybe the "inner product" could return a Scalar // instead of a 1x1 matrix ?? // Pro: more natural for the user // Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix // product ends up to a row-vector times col-vector product... To tackle this use // case, we could have a specialization for Block with: operator=(Scalar x); namespace internal { template struct traits > : traits::ReturnType,1,1> > {}; } template class GeneralProduct : internal::no_assignment_operator, public Matrix::ReturnType,1,1> { typedef Matrix::ReturnType,1,1> Base; public: GeneralProduct(const Lhs& lhs, const Rhs& rhs) { EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); } /** Convertion to scalar */ operator const typename Base::Scalar() const { return Base::coeff(0,0); } }; /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ namespace internal { template struct outer_product_selector; template struct traits > : traits, Lhs, Rhs> > {}; } template class GeneralProduct : public ProductBase, Lhs, Rhs> { public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) { EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) } template void scaleAndAddTo(Dest& dest, Scalar alpha) const { internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); } }; namespace internal { template<> struct outer_product_selector { template static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename Dest::Index Index; // FIXME make sure lhs is sequentially stored // FIXME not very good if rhs is real and lhs complex while alpha is real too const Index cols = dest.cols(); for (Index j=0; j struct outer_product_selector { template static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename Dest::Index Index; // FIXME make sure rhs is sequentially stored // FIXME not very good if lhs is real and rhs complex while alpha is real too const Index rows = dest.rows(); for (Index i=0; i call fast BLAS-like colmajor routine * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine * 3 - all other cases are handled using a simple loop along the outer-storage direction. * Therefore we need a lower level meta selector. * Furthermore, if the matrix is the rhs, then the product has to be transposed. */ namespace internal { template struct traits > : traits, Lhs, Rhs> > {}; template struct gemv_selector; } // end namespace internal template class GeneralProduct : public ProductBase, Lhs, Rhs> { public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) { // EIGEN_STATIC_ASSERT((internal::is_same::value), // YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) } enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; typedef typename internal::conditional::type MatrixType; template void scaleAndAddTo(Dest& dst, Scalar alpha) const { eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); } }; namespace internal { // The vector is on the left => transposition template struct gemv_selector { template static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { Transpose destT(dest); enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; gemv_selector ::run(GeneralProduct,Transpose, GemvProduct> (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); } }; template struct gemv_static_vector_if; template struct gemv_static_vector_if { EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } }; template struct gemv_static_vector_if { EIGEN_STRONG_INLINE Scalar* data() { return 0; } }; template struct gemv_static_vector_if { internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } }; template<> struct gemv_selector { template static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename ProductType::Index Index; typedef typename ProductType::LhsScalar LhsScalar; typedef typename ProductType::RhsScalar RhsScalar; typedef typename ProductType::Scalar ResScalar; typedef typename ProductType::RealScalar RealScalar; typedef typename ProductType::ActualLhsType ActualLhsType; typedef typename ProductType::ActualRhsType ActualRhsType; typedef typename ProductType::LhsBlasTraits LhsBlasTraits; typedef typename ProductType::RhsBlasTraits RhsBlasTraits; typedef Map, Aligned> MappedDest; const ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); const ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) * RhsBlasTraits::extractScalarFactor(prod.rhs()); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal }; gemv_static_vector_if static_dest; bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0)); bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; RhsScalar compatibleAlpha = get_factor::run(actualAlpha); ResScalar* actualDestPtr; bool freeDestPtr = false; if (evalToDest) { actualDestPtr = &dest.coeffRef(0); } else { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN int size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif if((actualDestPtr = static_dest.data())==0) { freeDestPtr = true; actualDestPtr = ei_aligned_stack_new(ResScalar,dest.size()); } if(!alphaIsCompatible) { MappedDest(actualDestPtr, dest.size()).setZero(); compatibleAlpha = RhsScalar(1); } else MappedDest(actualDestPtr, dest.size()) = dest; } general_matrix_vector_product ::run( actualLhs.rows(), actualLhs.cols(), &actualLhs.coeffRef(0,0), actualLhs.outerStride(), actualRhs.data(), actualRhs.innerStride(), actualDestPtr, 1, compatibleAlpha); if (!evalToDest) { if(!alphaIsCompatible) dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); else dest = MappedDest(actualDestPtr, dest.size()); if(freeDestPtr) ei_aligned_stack_delete(ResScalar, actualDestPtr, dest.size()); } } }; template<> struct gemv_selector { template static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename ProductType::LhsScalar LhsScalar; typedef typename ProductType::RhsScalar RhsScalar; typedef typename ProductType::Scalar ResScalar; typedef typename ProductType::Index Index; typedef typename ProductType::ActualLhsType ActualLhsType; typedef typename ProductType::ActualRhsType ActualRhsType; typedef typename ProductType::_ActualRhsType _ActualRhsType; typedef typename ProductType::LhsBlasTraits LhsBlasTraits; typedef typename ProductType::RhsBlasTraits RhsBlasTraits; typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) * RhsBlasTraits::extractScalarFactor(prod.rhs()); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 }; gemv_static_vector_if static_rhs; RhsScalar* actualRhsPtr; bool freeRhsPtr = false; if (DirectlyUseRhs) { actualRhsPtr = const_cast(&actualRhs.coeffRef(0)); } else { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN int size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif if((actualRhsPtr = static_rhs.data())==0) { freeRhsPtr = true; actualRhsPtr = ei_aligned_stack_new(RhsScalar, actualRhs.size()); } Map(actualRhsPtr, actualRhs.size()) = actualRhs; } general_matrix_vector_product ::run( actualLhs.rows(), actualLhs.cols(), &actualLhs.coeffRef(0,0), actualLhs.outerStride(), actualRhsPtr, 1, &dest.coeffRef(0,0), dest.innerStride(), actualAlpha); if((!DirectlyUseRhs) && freeRhsPtr) ei_aligned_stack_delete(RhsScalar, actualRhsPtr, prod.rhs().size()); } }; template<> struct gemv_selector { template static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename Dest::Index Index; // TODO makes sure dest is sequentially stored in memory, otherwise use a temp const Index size = prod.rhs().rows(); for(Index k=0; k struct gemv_selector { template static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { typedef typename Dest::Index Index; // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp const Index rows = prod.rows(); for(Index i=0; i template inline const typename ProductReturnType::Type MatrixBase::operator*(const MatrixBase &other) const { // A note regarding the function declaration: In MSVC, this function will sometimes // not be inlined since DenseStorage is an unwindable object for dynamic // matrices and product types are holding a member to store the result. // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. enum { ProductIsValid = Derived::ColsAtCompileTime==Dynamic || OtherDerived::RowsAtCompileTime==Dynamic || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) }; // note to the lost user: // * for a dot product use: v1.dot(v2) // * for a coeff-wise product use: v1.cwiseProduct(v2) EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) #ifdef EIGEN_DEBUG_PRODUCT internal::product_type::debug(); #endif return typename ProductReturnType::Type(derived(), other.derived()); } /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * * The returned product will behave like any other expressions: the coefficients of the product will be * computed once at a time as requested. This might be useful in some extremely rare cases when only * a small and no coherent fraction of the result's coefficients have to be computed. * * \warning This version of the matrix product can be much much slower. So use it only if you know * what you are doing and that you measured a true speed improvement. * * \sa operator*(const MatrixBase&) */ template template const typename LazyProductReturnType::Type MatrixBase::lazyProduct(const MatrixBase &other) const { enum { ProductIsValid = Derived::ColsAtCompileTime==Dynamic || OtherDerived::RowsAtCompileTime==Dynamic || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) }; // note to the lost user: // * for a dot product use: v1.dot(v2) // * for a coeff-wise product use: v1.cwiseProduct(v2) EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) return typename LazyProductReturnType::Type(derived(), other.derived()); } #endif // EIGEN_PRODUCT_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/ProductBase.h000066400000000000000000000255451172143270300221320ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_PRODUCTBASE_H #define EIGEN_PRODUCTBASE_H /** \class ProductBase * \ingroup Core_Module * */ namespace internal { template struct traits > { typedef MatrixXpr XprKind; typedef typename remove_all<_Lhs>::type Lhs; typedef typename remove_all<_Rhs>::type Rhs; typedef typename scalar_product_traits::ReturnType Scalar; typedef typename promote_storage_type::StorageKind, typename traits::StorageKind>::ret StorageKind; typedef typename promote_index_type::Index, typename traits::Index>::type Index; enum { RowsAtCompileTime = traits::RowsAtCompileTime, ColsAtCompileTime = traits::ColsAtCompileTime, MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = traits::MaxColsAtCompileTime, Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, // Note that EvalBeforeNestingBit and NestByRefBit // are not used in practice because nested is overloaded for products CoeffReadCost = 0 // FIXME why is it needed ? }; }; } #define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ typedef ProductBase Base; \ EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ typedef typename Base::LhsNested LhsNested; \ typedef typename Base::_LhsNested _LhsNested; \ typedef typename Base::LhsBlasTraits LhsBlasTraits; \ typedef typename Base::ActualLhsType ActualLhsType; \ typedef typename Base::_ActualLhsType _ActualLhsType; \ typedef typename Base::RhsNested RhsNested; \ typedef typename Base::_RhsNested _RhsNested; \ typedef typename Base::RhsBlasTraits RhsBlasTraits; \ typedef typename Base::ActualRhsType ActualRhsType; \ typedef typename Base::_ActualRhsType _ActualRhsType; \ using Base::m_lhs; \ using Base::m_rhs; template class ProductBase : public MatrixBase { public: typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) typedef typename Lhs::Nested LhsNested; typedef typename internal::remove_all::type _LhsNested; typedef internal::blas_traits<_LhsNested> LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; typedef typename internal::remove_all::type _ActualLhsType; typedef typename internal::traits::Scalar LhsScalar; typedef typename Rhs::Nested RhsNested; typedef typename internal::remove_all::type _RhsNested; typedef internal::blas_traits<_RhsNested> RhsBlasTraits; typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename internal::remove_all::type _ActualRhsType; typedef typename internal::traits::Scalar RhsScalar; // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; public: typedef typename Base::PlainObject PlainObject; ProductBase(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { eigen_assert(lhs.cols() == rhs.rows() && "invalid matrix product" && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); } inline Index rows() const { return m_lhs.rows(); } inline Index cols() const { return m_rhs.cols(); } template inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } template inline void addTo(Dest& dst) const { scaleAndAddTo(dst,1); } template inline void subTo(Dest& dst) const { scaleAndAddTo(dst,-1); } template inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { derived().scaleAndAddTo(dst,alpha); } const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } // Implicit conversion to the nested type (trigger the evaluation of the product) operator const PlainObject& () const { m_result.resize(m_lhs.rows(), m_rhs.cols()); derived().evalTo(m_result); return m_result; } const Diagonal diagonal() const { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } template const Diagonal diagonal() const { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } const Diagonal diagonal(Index index) const { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression typename Base::CoeffReturnType coeff(Index row, Index col) const { #ifdef EIGEN2_SUPPORT return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); #else EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeff(row,col); #endif } typename Base::CoeffReturnType coeff(Index i) const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeff(i); } const Scalar& coeffRef(Index row, Index col) const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeffRef(row,col); } const Scalar& coeffRef(Index i) const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeffRef(i); } protected: const LhsNested m_lhs; const RhsNested m_rhs; mutable PlainObject m_result; }; // here we need to overload the nested rule for products // such that the nested type is a const reference to a plain matrix namespace internal { template struct nested, N, PlainObject> { typedef PlainObject const& type; }; } template class ScaledProduct; // Note that these two operator* functions are not defined as member // functions of ProductBase, because, otherwise we would have to // define all overloads defined in MatrixBase. Furthermore, Using // "using Base::operator*" would not work with MSVC. // // Also note that here we accept any compatible scalar types template const ScaledProduct operator*(const ProductBase& prod, typename Derived::Scalar x) { return ScaledProduct(prod.derived(), x); } template typename internal::enable_if::value, const ScaledProduct >::type operator*(const ProductBase& prod, typename Derived::RealScalar x) { return ScaledProduct(prod.derived(), x); } template const ScaledProduct operator*(typename Derived::Scalar x,const ProductBase& prod) { return ScaledProduct(prod.derived(), x); } template typename internal::enable_if::value, const ScaledProduct >::type operator*(typename Derived::RealScalar x,const ProductBase& prod) { return ScaledProduct(prod.derived(), x); } namespace internal { template struct traits > : traits, typename NestedProduct::_LhsNested, typename NestedProduct::_RhsNested> > { typedef typename traits::StorageKind StorageKind; }; } template class ScaledProduct : public ProductBase, typename NestedProduct::_LhsNested, typename NestedProduct::_RhsNested> { public: typedef ProductBase, typename NestedProduct::_LhsNested, typename NestedProduct::_RhsNested> Base; typedef typename Base::Scalar Scalar; typedef typename Base::PlainObject PlainObject; // EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) ScaledProduct(const NestedProduct& prod, Scalar x) : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} template inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,m_alpha); } template inline void addTo(Dest& dst) const { scaleAndAddTo(dst,m_alpha); } template inline void subTo(Dest& dst) const { scaleAndAddTo(dst,-m_alpha); } template inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { m_prod.derived().scaleAndAddTo(dst,alpha); } const Scalar& alpha() const { return m_alpha; } protected: const NestedProduct& m_prod; Scalar m_alpha; }; /** \internal * Overloaded to perform an efficient C = (A*B).lazy() */ template template Derived& MatrixBase::lazyAssign(const ProductBase& other) { other.derived().evalTo(derived()); return derived(); } #endif // EIGEN_PRODUCTBASE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Random.h000066400000000000000000000137421172143270300211330ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_RANDOM_H #define EIGEN_RANDOM_H namespace internal { template struct scalar_random_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) template inline const Scalar operator() (Index, Index = 0) const { return random(); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; } // end namespace internal /** \returns a random matrix expression * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() */ template inline const CwiseNullaryOp::Scalar>, Derived> DenseBase::Random(Index rows, Index cols) { return NullaryExpr(rows, cols, internal::scalar_random_op()); } /** \returns a random vector expression * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Random() should be used * instead. * * Example: \include MatrixBase_random_int.cpp * Output: \verbinclude MatrixBase_random_int.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary vector whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() */ template inline const CwiseNullaryOp::Scalar>, Derived> DenseBase::Random(Index size) { return NullaryExpr(size, internal::scalar_random_op()); } /** \returns a fixed-size random matrix or vector expression * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_random.cpp * Output: \verbinclude MatrixBase_random.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) */ template inline const CwiseNullaryOp::Scalar>, Derived> DenseBase::Random() { return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); } /** Sets all coefficients in this expression to random values. * * Example: \include MatrixBase_setRandom.cpp * Output: \verbinclude MatrixBase_setRandom.out * * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index) */ template inline Derived& DenseBase::setRandom() { return *this = Random(rows(), cols()); } /** Resizes to the given \a size, and sets all coefficients in this expression to random values. * * \only_for_vectors * * Example: \include Matrix_setRandom_int.cpp * Output: \verbinclude Matrix_setRandom_int.out * * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setRandom(Index size) { resize(size); return setRandom(); } /** Resizes to the given size, and sets all coefficients in this expression to random values. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setRandom_int_int.cpp * Output: \verbinclude Matrix_setRandom_int_int.out * * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setRandom(Index rows, Index cols) { resize(rows, cols); return setRandom(); } #endif // EIGEN_RANDOM_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Redux.h000066400000000000000000000332571172143270300210050ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_REDUX_H #define EIGEN_REDUX_H namespace internal { // TODO // * implement other kind of vectorization // * factorize code /*************************************************************************** * Part 1 : the logic deciding a strategy for vectorization and unrolling ***************************************************************************/ template struct redux_traits { public: enum { PacketSize = packet_traits::size, InnerMaxSize = int(Derived::IsRowMajor) ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime }; enum { MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) && (functor_traits::PacketAccess), MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize }; public: enum { Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal) : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(DefaultTraversal) }; public: enum { Cost = ( Derived::SizeAtCompileTime == Dynamic || Derived::CoeffReadCost == Dynamic || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) ) ? Dynamic : Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) }; public: enum { Unrolling = Cost != Dynamic && Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling }; }; /*************************************************************************** * Part 2 : unrollers ***************************************************************************/ /*** no vectorization ***/ template struct redux_novec_unroller { enum { HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; EIGEN_STRONG_INLINE static Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), redux_novec_unroller::run(mat,func)); } }; template struct redux_novec_unroller { enum { outer = Start / Derived::InnerSizeAtCompileTime, inner = Start % Derived::InnerSizeAtCompileTime }; typedef typename Derived::Scalar Scalar; EIGEN_STRONG_INLINE static Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); } }; // This is actually dead code and will never be called. It is required // to prevent false warnings regarding failed inlining though // for 0 length run() will never be called at all. template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; EIGEN_STRONG_INLINE static Scalar run(const Derived&, const Func&) { return Scalar(); } }; /*** vectorization ***/ template struct redux_vec_unroller { enum { PacketSize = packet_traits::size, HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; EIGEN_STRONG_INLINE static PacketScalar run(const Derived &mat, const Func& func) { return func.packetOp( redux_vec_unroller::run(mat,func), redux_vec_unroller::run(mat,func) ); } }; template struct redux_vec_unroller { enum { index = Start * packet_traits::size, outer = index / int(Derived::InnerSizeAtCompileTime), inner = index % int(Derived::InnerSizeAtCompileTime), alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned }; typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; EIGEN_STRONG_INLINE static PacketScalar run(const Derived &mat, const Func&) { return mat.template packetByOuterInner(outer, inner); } }; /*************************************************************************** * Part 3 : implementation of all cases ***************************************************************************/ template::Traversal, int Unrolling = redux_traits::Unrolling > struct redux_impl; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res; res = mat.coeffByOuterInner(0, 0); for(Index i = 1; i < mat.innerSize(); ++i) res = func(res, mat.coeffByOuterInner(0, i)); for(Index i = 1; i < mat.outerSize(); ++i) for(Index j = 0; j < mat.innerSize(); ++j) res = func(res, mat.coeffByOuterInner(i, j)); return res; } }; template struct redux_impl : public redux_novec_unroller {}; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; typedef typename Derived::Index Index; static Scalar run(const Derived& mat, const Func& func) { const Index size = mat.size(); eigen_assert(size && "you are using an empty matrix"); const Index packetSize = packet_traits::size; const Index alignedStart = first_aligned(mat); enum { alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) ? Aligned : Unaligned }; const Index alignedSize = ((size-alignedStart)/packetSize)*packetSize; const Index alignedEnd = alignedStart + alignedSize; Scalar res; if(alignedSize) { PacketScalar packet_res = mat.template packet(alignedStart); for(Index index = alignedStart + packetSize; index < alignedEnd; index += packetSize) packet_res = func.packetOp(packet_res, mat.template packet(index)); res = func.predux(packet_res); for(Index index = 0; index < alignedStart; ++index) res = func(res,mat.coeff(index)); for(Index index = alignedEnd; index < size; ++index) res = func(res,mat.coeff(index)); } else // too small to vectorize anything. // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. { res = mat.coeff(0); for(Index index = 1; index < size; ++index) res = func(res,mat.coeff(index)); } return res; } }; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; typedef typename Derived::Index Index; static Scalar run(const Derived& mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); const Index outerSize = mat.outerSize(); enum { packetSize = packet_traits::size }; const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; Scalar res; if(packetedInnerSize) { PacketScalar packet_res = mat.template packet(0,0); for(Index j=0; j(j,i)); res = func.predux(packet_res); for(Index j=0; j::run(mat, func); } return res; } }; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; enum { PacketSize = packet_traits::size, Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; EIGEN_STRONG_INLINE static Scalar run(const Derived& mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res = func.predux(redux_vec_unroller::run(mat,func)); if (VectorizedSize != Size) res = func(res,redux_novec_unroller::run(mat,func)); return res; } }; } // end namespace internal /*************************************************************************** * Part 4 : public API ***************************************************************************/ /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be * an associative operator. Both current STL and TR1 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ template template EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type DenseBase::redux(const Func& func) const { typedef typename internal::remove_all::type ThisNested; return internal::redux_impl ::run(derived(), func); } /** \returns the minimum of all coefficients of *this */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { return this->redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of *this */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { return this->redux(Eigen::internal::scalar_max_op()); } /** \returns the sum of all coefficients of *this * * \sa trace(), prod(), mean() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); return this->redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this * * \sa trace(), prod(), sum() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); } /** \returns the product of all coefficients of *this * * Example: \include MatrixBase_prod.cpp * Output: \verbinclude MatrixBase_prod.out * * \sa sum(), mean(), trace() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); return this->redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. * * \c *this can be any matrix, not necessarily square. * * \sa diagonal(), sum() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar MatrixBase::trace() const { return derived().diagonal().sum(); } #endif // EIGEN_REDUX_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Replicate.h000066400000000000000000000162361172143270300216240ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_REPLICATE_H #define EIGEN_REPLICATE_H /** * \class Replicate * \ingroup Core_Module * * \brief Expression of the multiple replication of a matrix or vector * * \param MatrixType the type of the object we are replicating * * This class represents an expression of the multiple replication of a matrix or vector. * It is the return type of DenseBase::replicate() and most of the time * this is the only way it is used. * * \sa DenseBase::replicate() */ namespace internal { template struct traits > : traits { typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename nested::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic ? Dynamic : RowFactor * MatrixType::RowsAtCompileTime, ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic ? Dynamic : ColFactor * MatrixType::ColsAtCompileTime, //FIXME we don't propagate the max sizes !!! MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; } template class Replicate : public internal::dense_xpr_base< Replicate >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) template inline explicit Replicate(const OriginalMatrixType& matrix) : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); } template inline Replicate(const OriginalMatrixType& matrix, int rowFactor, int colFactor) : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) } inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } inline Scalar coeff(Index row, Index col) const { // try to avoid using modulo; this is a pure optimization strategy const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 : RowFactor==1 ? row : row%m_matrix.rows(); const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 : ColFactor==1 ? col : col%m_matrix.cols(); return m_matrix.coeff(actual_row, actual_col); } template inline PacketScalar packet(Index row, Index col) const { const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 : RowFactor==1 ? row : row%m_matrix.rows(); const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 : ColFactor==1 ? col : col%m_matrix.cols(); return m_matrix.template packet(actual_row, actual_col); } protected: const typename MatrixType::Nested m_matrix; const internal::variable_if_dynamic m_rowFactor; const internal::variable_if_dynamic m_colFactor; }; /** * \return an expression of the replication of \c *this * * Example: \include MatrixBase_replicate.cpp * Output: \verbinclude MatrixBase_replicate.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate */ template template inline const Replicate DenseBase::replicate() const { return Replicate(derived()); } /** * \return an expression of the replication of \c *this * * Example: \include MatrixBase_replicate_int_int.cpp * Output: \verbinclude MatrixBase_replicate_int_int.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate */ template inline const Replicate DenseBase::replicate(Index rowFactor,Index colFactor) const { return Replicate(derived(),rowFactor,colFactor); } /** * \return an expression of the replication of each column (or row) of \c *this * * Example: \include DirectionWise_replicate_int.cpp * Output: \verbinclude DirectionWise_replicate_int.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate */ template const typename VectorwiseOp::ReplicateReturnType VectorwiseOp::replicate(Index factor) const { return typename VectorwiseOp::ReplicateReturnType (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); } #endif // EIGEN_REPLICATE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/ReturnByValue.h000066400000000000000000000074451172143270300224650ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // Copyright (C) 2009-2010 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_RETURNBYVALUE_H #define EIGEN_RETURNBYVALUE_H /** \class ReturnByValue * \ingroup Core_Module * */ namespace internal { template struct traits > : public traits::ReturnType> { enum { // We're disabling the DirectAccess because e.g. the constructor of // the Block-with-DirectAccess expression requires to have a coeffRef method. // Also, we don't want to have to implement the stride stuff. Flags = (traits::ReturnType>::Flags | EvalBeforeNestingBit) & ~DirectAccessBit }; }; /* The ReturnByValue object doesn't even have a coeff() method. * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? */ template struct nested, n, PlainObject> { typedef typename traits::ReturnType type; }; } // end namespace internal template class ReturnByValue : public internal::dense_xpr_base< ReturnByValue >::type { public: typedef typename internal::traits::ReturnType ReturnType; typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) template inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } inline Index rows() const { return static_cast(this)->rows(); } inline Index cols() const { return static_cast(this)->cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN #define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT class Unusable{ Unusable(const Unusable&) {} Unusable& operator=(const Unusable&) {return *this;} }; const Unusable& coeff(Index) const { return *reinterpret_cast(this); } const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } #endif }; template template Derived& DenseBase::operator=(const ReturnByValue& other) { other.evalTo(derived()); return derived(); } #endif // EIGEN_RETURNBYVALUE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Reverse.h000066400000000000000000000202711172143270300213210ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2009 Ricard Marxer // Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_REVERSE_H #define EIGEN_REVERSE_H /** \class Reverse * \ingroup Core_Module * * \brief Expression of the reverse of a vector or matrix * * \param MatrixType the type of the object of which we are taking the reverse * * This class represents an expression of the reverse of a vector. * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() * and most of the time this is the only way it is used. * * \sa MatrixBase::reverse(), VectorwiseOp::reverse() */ namespace internal { template struct traits > : traits { typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename nested::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, // let's enable LinearAccess only with vectorization because of the product overhead LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) ? LinearAccessBit : 0, Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; template struct reverse_packet_cond { static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } }; template struct reverse_packet_cond { static inline PacketScalar run(const PacketScalar& x) { return x; } }; } // end namespace internal template class Reverse : public internal::dense_xpr_base< Reverse >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) using Base::IsRowMajor; // next line is necessary because otherwise const version of operator() // is hidden by non-const version defined in this file using Base::operator(); protected: enum { PacketSize = internal::packet_traits::size, IsColMajor = !IsRowMajor, ReverseRow = (Direction == Vertical) || (Direction == BothDirections), ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, ReversePacket = (Direction == BothDirections) || ((Direction == Vertical) && IsColMajor) || ((Direction == Horizontal) && IsRowMajor) }; typedef internal::reverse_packet_cond reverse_packet; public: inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } inline Index innerStride() const { return -m_matrix.innerStride(); } inline Scalar& operator()(Index row, Index col) { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return coeffRef(row, col); } inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, ReverseCol ? m_matrix.cols() - col - 1 : col); } inline CoeffReturnType coeff(Index row, Index col) const { return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, ReverseCol ? m_matrix.cols() - col - 1 : col); } inline CoeffReturnType coeff(Index index) const { return m_matrix.coeff(m_matrix.size() - index - 1); } inline Scalar& coeffRef(Index index) { return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); } inline Scalar& operator()(Index index) { eigen_assert(index >= 0 && index < m_matrix.size()); return coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return reverse_packet::run(m_matrix.template packet( ReverseRow ? m_matrix.rows() - row - OffsetRow : row, ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_matrix.const_cast_derived().template writePacket( ReverseRow ? m_matrix.rows() - row - OffsetRow : row, ReverseCol ? m_matrix.cols() - col - OffsetCol : col, reverse_packet::run(x)); } template inline const PacketScalar packet(Index index) const { return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); } template inline void writePacket(Index index, const PacketScalar& x) { m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); } protected: const typename MatrixType::Nested m_matrix; }; /** \returns an expression of the reverse of *this. * * Example: \include MatrixBase_reverse.cpp * Output: \verbinclude MatrixBase_reverse.out * */ template inline typename DenseBase::ReverseReturnType DenseBase::reverse() { return derived(); } /** This is the const version of reverse(). */ template inline const typename DenseBase::ConstReverseReturnType DenseBase::reverse() const { return derived(); } /** This is the "in place" version of reverse: it reverses \c *this. * * In most cases it is probably better to simply use the reversed expression * of a matrix. However, when reversing the matrix data itself is really needed, * then this "in-place" version is probably the right choice because it provides * the following additional features: * - less error prone: doing the same operation with .reverse() requires special care: * \code m = m.reverse().eval(); \endcode * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) * - it allows future optimizations (cache friendliness, etc.) * * \sa reverse() */ template inline void DenseBase::reverseInPlace() { derived() = derived().reverse().eval(); } #endif // EIGEN_REVERSE_H mldemos-0.4.3/_3rdParty/Eigen/src/Core/Select.h000066400000000000000000000146351172143270300211340ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_SELECT_H #define EIGEN_SELECT_H /** \class Select * \ingroup Core_Module * * \brief Expression of a coefficient wise version of the C++ ternary operator ?: * * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix * \param ThenMatrixType the type of the \em then expression * \param ElseMatrixType the type of the \em else expression * * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:. * It is the return type of DenseBase::select() and most of the time this is the only way it is used. * * \sa DenseBase::select(const DenseBase&, const DenseBase&) const */ namespace internal { template struct traits > : traits { typedef typename traits::Scalar Scalar; typedef Dense StorageKind; typedef typename traits::XprKind XprKind; typedef typename ConditionMatrixType::Nested ConditionMatrixNested; typedef typename ThenMatrixType::Nested ThenMatrixNested; typedef typename ElseMatrixType::Nested ElseMatrixNested; enum { RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime, ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, CoeffReadCost = traits::type>::CoeffReadCost + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, traits::type>::CoeffReadCost) }; }; } template class Select : internal::no_assignment_operator, public internal::dense_xpr_base< Select >::type { public: typedef typename internal::dense_xpr_base